Showing posts with label development. Show all posts
Showing posts with label development. Show all posts

December 2, 2014

UK Python Training Open Day and Lunch

Regular readers (both?) know that I live in the USA but hail from the UK, where I still return regularly to stay in touch with family and friends. So to dip a toe in the UK training waters I booked a room (rather a nice one, as those who have attended other events I organized will not be surprised to learn) and put out an announcement that I was running a Python Programming Skills Lab. You could have booked a place here. Of course if this were the movies, the spirit of “if you build it they will come” would rule and I could welcome those wishing to drink at the Python fount. But it isn't.

So
a) I am not a marketing genius;
b) this is not the movies.
Result: I am now planning to spend the day in said reserved room, working on my current open source project, whose sadly neglected repository can be found in a weed-infested corner of Github. This is the code I used as a script for the videos which (if you are reading my blog) you should see advertised up at top right. The code is presented as iPython Notebooks, and only some of them are properly documented in interspersed Markdown cells, so if I end up spending the day alone then at least some sensible purpose will have been served.

With that in mind the Skills Lab is now metamorphosing into an open Python Training Day. I understand this is very short notice (I'm not very good at operations either, go figure), but if you have any interest in either receiving Python training or having such training presented to a target group I would be delighted to talk with you on Tuesday December 9, 2014 at any time between 10:00 am and 4:30 pm at the Church House Conference Centre in Westminster.

If you would like to join me for lunch then please sign up (there are 12 places for lunch) and arrive no later than 12:30. If you simply want to drop in and say hello (or, better still, help work on the codebase) then feel free to arrive at any time during the advertised hours and stay as long as you like (but please do sign up for lunch if you plan to eat). It would be helpful if you reserved a drop-in place even if you aren't coming to eat. Those with an interest in beer might want to arrive towards the end of the proceedings so a post-event excursion to a licensed hostelry can be entertained if appropriate.

The room reserved for this event is absolutely delightful, with a view across the Dean's Yard. I welcome all Python friends and anyone who would like to get to know me professionally to visit at some convenient time during that day. But do remember to reserve a place if you want lunch!

I have had very little time to work on the Github repository since the videos were shot, and yearn for an army of Internet interns to help me improve what I believe are useful open-source training materials. In the absence of visitors that day, any spare time I have on that day will go to improve the Notebooks, so at the very least the curated Notebook collection will become more useful.

August 6, 2010

Tests That Test Your Tests

I just had an interesting experience with Steve Miller, the technical editor of the Python classes I am writing for O'Reilly School of Technology. We are just getting to the end of the second of four courses, and I like to think that we are moving right along: in the final lesson students write a simple GUI-based program that searches for and displays e-mail messages stored in a MySQL database.

I introduced test-driven development in the second course. Not only does this encourage good habits in the students, it also makes it somewhat easier to test some of their exercises (though I still do not have a good approach to testing Tkinter-based GUI applications). In time-honored fashion we start with tests and a program full of stubs, and then expand the stubs to pass the tests. For the email database the initial API is very simple: there is one function to store messages and two others to retrieve them, by primary key and Message-Id.

In the final chapter I start out with a very simple database table that stores the body of the message as a LONGTEXT column. The only other columns in the table (to start with—it gets more complex later) are the automatically-generated primary key and the Message-Id Header. The tests use a setUp() method that completely re-creates the database table and populates it from messages stored in a bunch of files:

 FILESPEC = "V:/Python2/Lesson12/MailData/*.eml"  
 class testRealEmail_traffic(unittest.TestCase):  
   def setUp(self):  
     """  
     Reads an arbitrary number of mail messages and  
     stores them in a brand new messages table.  
     DANGER: Any existing message table WILL be lost.  
     """  
     curs.execute("DROP TABLE IF EXISTS message")  
     conn.commit()  
     curs.execute(TBLDEF)  
     conn.commit()  
     files = glob(FILESPEC)  
     self.msgids = {} # Keyed by message_id  
     self.message_ids = {} # keyed by id  
     for f in files:  
       ff = open(f)  
       text = ff.read()  
       msg = message_from_string(text)  
       id = self.msgids[msg['message-id']] = maildb.store(msg)  
       self.message_ids[id] = msg['message-id']  

There were two relatively simple tests, one to test each of the retrieval functions in a fairly simplistic way by verifying the correspondence between the primary key values and the Message-Id headers using the msgids and message_ids dicts created during the set-up. The initial stub under test only implemented the store() function, so these tests were initially expected to fail:

   def test_message_ids(self):  
     """  
     Verify that items retrieved by id have the correct Message-ID.  
     """   
     for message_id in self.msgids.keys():  
       pk, msg = maildb.msg_by_id(self.msgids[message_id])   
       self.assertEqual(msg['message-id'], message_id)  
   def test_ids(self):  
     """  
     Verify that items retrieved by message_id have the correct Message-ID.  
     """  
     for id in self.message_ids.keys():  
       pk, msg = maildb.msg_by_message_id(self.message_ids[id])  
       self.assertEqual(msg['message-id'], self.message_ids[id])  

Steve and I had both run this code under much the same conditions as the students would, and verified that the tests did indeed fail due to the AttributeError exceptions raised by the missing msg_by_id() and msg_by_message_id() functions. Later steps have the student implement these functions, which makes the tests pass.

We were somewhat surprised to find when Steve ran his final checks that the tests were now passing, even though he had reverted to the original module with no implementations of the message retrieval functions! It took me the best part of an hour chatting with Steve to eliminate everything I could think of that might be wrong: no .pyc files left lying around, no odd path settings that allowed import from other copies of the code, and so on.

We finally tracked the issue down to something stupidly simple, as is often the case with bugs that have you scratching your head for an extended period: for production purposes the data files had been moved to an area where all students could share them (each student has their own V: directory). This meant that the setUp() method was not inserting any rows into the newly-created message table. The empty table in turn meant that neither test_message_ids() nor test_ids() was running the the body of the for loop, and consequently no AttributeError exceptions were being raised. The tests were passing even though the functions they were supposed to test had not been implemented!

My solution to this was to add a further test to verify that the table was not empty. That way, even if the other tests passed, this one would fail:

   def test_not_empty(self):  
     """  
     Verify that the setUp method actually created some messages.  
     If it finds no files there will be no messages in the table,  
     the loop bodies in the other tests will never run, and potential  
     errors will never be discovered.  
     """  
     curs.execute("SELECT COUNT(*) FROM message")  
     messagect = curs.fetchone()[0]  
     self.assertGreater(messagect, 0, "Database message table is empty")  

The check could have been added to one of the other tests but it seemed to make more sense to keep it separate, since several tests relied on the table having been populated.

In this case the error condition was that the test were passing! I am happy about this because it clearly demonstrates the value of test-driven development, even though the result I was getting was normally the desired goal of testing. It has also taught me to be more careful about tests in loops: if there is no guarantee that the loop body will execute then the tests inside it can be completely useless.

September 27, 2009

Lending Pythonistas

Too often I hear people bemoaning their inability to change the world, so I wanted to bring Kiva, and specifically the Pythonistas team, to your attention because if you have even a modest amount of money to spare you can put it to use again and again to help worthy enterprises, typically closely allied with their local community.

I started lending money through Kiva a while ago, and more recently joined its Pythonistas team. I suggested starting such a team shortly after I joined Kiva, but it took Anna Martelli's energy to actually get it off the ground, and I received my invitation a couple of months ago - thanks, Anna! If you decide you want to become a "Kiva Pythonista" all you have to do is follow this link.

Even as a Kiva Pythonista you still decide to whom you want to lend money, you simply say you want your loans to be counted as a part of the Pythonista effort. The enterprises you will fund are typically far from hi-tech: here are some of the groups I am currently funding to give you some idea of the kinds of activity you can support.

Secretarial Services in Uganda
Second-Hand Clothing in Guatemala
Fish Retailing in Senegal
Cattle Farming in Azerbaijan
A Grocery Store in Cambodia
Animal Rearing in Tajikistan
A General Store in Togo
A Cooperative Bank in Bolivia

This came to mind because I got an email this morning reminding me that I had received repayments of $150, and so I am just about to use the Kiva site to lend those repaid funds to new borrowers, keeping my money actively at work. And now I can do it as a Pythonista!

January 27, 2009

Snakebite.org Announced: Get Bitten by the Python Bug!

Things are looking up! I mentioned Trent Nelson's snakebite.org in my Python Magazine column a while ago, but at that point everything was still in stealth mode, so you couldn't get much information about what was going on from the web site.

That's all over now, because yesterday Trent mailed the python-dev list to announce the forthcoming availability of the network, which far from being "a couple of clunky old boxes off eBay" turns out to be the makings of a comprehensive distributed test and development network, with hardware and software contributions from major companies, that's going to be the envy of the open source world.

I know that Trent has larger plans for snakebite.org, but on behalf of the Python community I would like to thank him (and a cast of many others) not only for his munificence but also for the incredibly hard work that's been done to bring this project to fruition.

December 4, 2008

Python 3.0 Is Out

Even though I am on vacation this is worth a quick note. After long efforts by many developers Python 3.0 was released today!

I posted a short article a while ago about 3.0 (in)compatibility, but the differences between 2.6 and 3.0 aren't so great. It's perfectly possible to write 3.0 code that will run on 2.6 too, as most of the language hasn't changed at all.

The preferred strategy for writing code that runs on both versions is to write in 2.6 and then apply the 2to3 converter and verify that it produces a correct 3.0 program. There's no guarantee that it will, so you may need to paraphrase the 2.6 code a few times before you get a transatable program.

Once all the third-party modules you and extensions you rely on are 3.0-ready, and you no longer have clients requiring 2.6 version of your software, you can simply drop the 2.6 compatibility requirement and start to make use of the few 3.0-only constructs that have been introduced.

July 12, 2008

PyPy Continues to Catch Up

Interesting news from the EuroPython sprints at Vilnius via Holger Krekel. PyPy supports Django well enough to run the Pinax application put together by an open source team coordinated by James Tauber. It's great to see Python expanding in so many directions at once. The future is definitelyto be interesting.

Django seems to be becoming one of the "how good is your implementation" tests for Python implementations. Not only are the PyPy team using it in this way, but IronPython and Jython are as well. Since Jython is now in alpha with a Python 2.5-compatible implementation the picture is looking better and better every day.

The one thing nobody has discussed much is the attitude of the PyPy, Jython and IronPython development teams to migration towards Python 3.0. Does it represent the next wave, or will it end up as an isolated development?

March 4, 2008

PyPy Catching Up ...

An interesting post on the PyPy (Python written in Python) blog explains that PyPy has finally, on carefully selected tests, benchmarked ever so slightly faster than CPython (1% faster on one test, 11% faster on the other).

It's also interesting to note that a 20% speedup is achieved by method caching, which avoids the need to create a new bound method every time a method is referenced relative to an instance. Apparently the same technique would be usable in CPython were it not for certain C modules directly modifying the __dict__ of new-style classes. I wonder if CPython could obtain an equivalent speed-up, and if so whether it would be worthwhile making the guilty C modules restrict themselves like PyPy does.

I have high hopes that within a year we will regularly be seeing benchmarks that show PyPy outperforming CPython.

If you can't wait for that, and can live with heavy restrictions on your use of the language, try RPython (another product of the fertile PyPy project, and one in which Stackless Python's Christian Tismer had a hand) which on occasion benchmarks faster than C!

January 8, 2008

Windmill Web Testing Framework

If what this page says is true then Windmill will be very well worth some investigation. Of course the major problem with the Python web world is that so much is going on it's simply impossible to keep up with everything! Of course WSGI lays the foundation for much else, and it appears that Zope 2 now plays well with others.

I think I might start trying to make shorter blog entries just to note the most interesting developments as PyPI (Cheese Shop) contributions fly past at a rate of knots.

In the past I have looked at TurboGears, and was impressed how easy it was to implement the functionality of another web site. Recently I have been doing a similar thing with Django. We are very fortunate to have two such capable frameworks available for our web developments, and I am going to try and make sure that they both get some coverage in Python Magazine.

December 19, 2007

Cheese Shop Doing Good Business

PyPi, the Python Package Index, is affectionately known as the Cheese Shop due to the the Python world's affinity with Monty Python and its tendency to relish obscure puns based on the sketches. I can't say I have ever liked the nickname, but PyPi is a valuable repository of often highly usable code and currently contains over 3,000 contributions. So it's worth a look.

The RSS feed contains the last thirty updates, which currently covers a 48-hour span--the feed appears to be updated once daily at 7 pm. So there's clearly a lot going on, and when I get time (note the ironic sound of hollow laughter ringing metaphorically in your ears) I shall be using the browse interface to take a closer look.

August 31, 2007

Python 3.0 First Alpha Build Available

Guido has just announced the availability of a public alpha of Python 3.0.

Please remember there are several things this does not mean:

  • Python 2.x is not obsolete. The series will continue through 2.6 (which will include backports of many Python 3 features) and probably 2.7. In fact the only guarantee is that there will be no releases after 2.9.x, as Guido has stated his dislike of the ambiguities inherent in a 2.10 release number.
  • Python 3 is not ready for production work. The alpha series is expected to last a considerable length of time, and even when Python 3 comes into production (in around a year from now if Guido's original schedule is maintained) 2.6 will be the major platform.
  • There should be no need to develop parallel source trees for your Python code. The 2.6 translator will have a "Python 3 warnings" mode, and if you ensure that this doesn't produce warnings you will be able to convert your code to Python 3 automatically using a conversion tool.
For a summary of other things you might like to know about Python 3 see Guido's blog.