Mario Boikov: IcecastRadio - Qt widget/Qt Quick example Icecast player

I've been toying with modeling a Qt application which supports both a traditional widget-based view and a quick-based (qml) view.

About IcecastRadio
The intention of this project/application is to demonstrate how important
it can be to design a model for your application. If the model is correctly
designed, it can be used from both traditional widget based UIs and
modern UIs built with Qt Quick without too much effort.

The advantage is of course that you can provide both a desktop application which integrates with the native look and feel of the OS and at the same time have a totally different experience UI-wise, for example in an embedded device by only changing the view-layer.

IcecastRadio is actually two applications, QtCast and QuickCast. QtCast implements the widget-based view and QuickCast the quick-based view. Both application depends on a third entity, the model. You'll see this division in the source code in form of three projects, qtcast, quickcast and model.

The application was successfully compiled against Qt 4.7-beta 1 and 2.

Source code
You'll find the source code at http://gitorious.org/icecastradio. The player code is released under the MIT license, clone and have fun. Please read the README file found in the repository for more information.

Screenshots
Must have...



Remark
The application lacks a lot of features that could be expected from a radio player, for example there is no way of sorting the list of stations nor any filtering can be applied. The intention was not to create a full blown Icecast player but to demonstrate how to create a model that is usable from both a widget-based application and a quick-based application.

Patches are welcome :)

Doug Hellmann: PyMOTW: re - Regular Expressions

Regular expressions are text matching patterns described with a
formal syntax. The patterns are interpreted as a set of instructions,
which are then executed with a string as input to produce a matching
subset or modified version of the original. The term “regular
expressions” is frequently shortened to as “regex” or “regexp” in
conversation. Expressions can include literal text matching,
repetition, pattern-composition, branching, and other sophisticated
rules. A large number of parsing problems are easier to solve with a
regular expression than by creating a special-purpose lexer and
parser.

Read more...


Richard Tew: Roguelike MUD progress #3

Previous post: Roguelike MUD progress #2.

Field of view emphasis is now row based, rather than tile based. However, I've also added the ability for tiles to have attached foreground and background colours. Really, the rendering needs to break all this down and minimise the number of switches made using different escape codes. For now, use of colour is limited, so updating the display does not seem slow or flickery like it was in the past before I batched updates.

I've also added simple NPCs, in this case three small green dragons that wander around the dungeon. For now, that's all they do, but they're good at highlighting rendering bugs.



Current TODO list:
  1. Add bursts of fire, using different tiles and colours to make use of a wide range of colours than the basic eight through dithering. It might be a good idea to write the tile/colour choosing logic in a way that can optionally use the xterm 256 colour mode, if the client can be detected as supporting it.
  2. Add option for NPCs to choose to attack, rather than move, when they are ticked.
  3. Add option for players to attack, rather than move.
  4. At the moment, player keypresses are executed as they come in from the client. They should instead be queued and executed at a fixed rate.

Richard Tew: Roguelike MUD progress #2

Previous post: Roguelike MUD progress.

I wasn't feeling very motivated when the time I had set aside tonight to work on this came around, but once I got into it I made pretty good progress. The bugs I listed yesterday are now fixed, and additionally the field of view emphasis is working. It's annoying that the stupid mistakes are the ones that take the longest to track down. In this case, absently writing or instead of and.
if y in self.drawRangesNew:
minX, maxX = self.drawRangesNew[y]
if x >= minX or x = maxX:
return True
Maybe I should reconsider minX = x = maxX, although it never quite seems right.


The FoV changes are not as optimal as they could be. Every tile in the post-move FoV tile set is individually marked up with escape codes, I should instead simply mark each row of qualifying tiles in one go.

Current TODO list:
  1. Clean up the FoV emphasis to be row-based, rather than tile-based.
  2. Add some objects and entities to the world, that can be interacted with. Entities should move to add life to the world.


Next post: Roguelike MUD progress #3

Richard Tew: Roguelike MUD progress

I finally found some more time to work on my roguelike MUD project. Tonight I managed to get proper multi-player support in, so that concurrently logged in players have their view of the game updated as other game objects change position. Up to this point the players mostly shared the world representation, and had separate state defining what was in it.


While the changes required are more or less fine, some didn't fit well into the existing game framework. I need to put some thought into cleaning those up.

Achievable next steps should hopefully be:
  1. Cleaning up the bugs.
    - Fix the incorrect menu related message that appears in the top telnet window shown in the screenshot.
    - When a player quits the game, the display of other observing players does not update to reflect it.
    - When an object moves, observing players are defined as those who have visited the tile the object moved to and currently have it on their display. Instead only observing players who have the object in their field of vision should see the movement.
  2. Polish the field of vision support.
    - The tiles that are in the field of vision should be distinct from those that are not (Smart Kobold uses this approach to good effect).
  3. Widen the corridors so players can pass each other.
  4. Add entities controlled by AI that move around of their own volition.
Really, in this day and age a game like this should be browser based (like 91). But getting side tracked into a non-game related endeavour to implement an equivalent canvas based display with a AJAX or COMET connection to the backend server, is something I have no time for just now.

Next post: Roguelike MUD progress #2

Ned Batchelder: Making good tar files on Windows

I work on Windows, and produce Python kits for various projects. Of course one of the kits is a source kit, as a .tar.gz. Python's distutils does a fine job of this, but it uses the native system command to tar up the files, and this means my tar files are from Windows.

The problem is that Windows doesn't know how to make tar files that look native on Unix: the permission bits aren't right, they come out as 0700:

drwx------ batcheln/100      0 2010-08-21 14:13 coverage-3.4b1/
-rwx------ batcheln/100    516 2010-08-08 09:36 coverage-3.4b1/AUTHORS.txt
...

The tar command let me set the mode bits in a command-line switch, which means I could set them in an environment variable, but that would make all the files have the same permission bits, and directories and files should be different.

To fix this problem, I wrote a distutils extension command. It turned out to be not difficult, distutils has good extensibility.

To make a new command, create a new package directory somewhere, I called my "distcmd". To make a command called "fixtar", you you derive a class from distutils.core.Command, name it fixtar, and put it in a file called fixtar.py. You have to provide three methods:

from distutils.core import Command
import shutil, tarfile

class fixtar(Command):
    """A new setup.py command to fix tar file permissions."""

    description = "Re-pack the tar file to have correct permissions."

    user_options = []

    def initialize_options(self):
        """Required by Command, even though I have nothing to add."""
        pass

    def finalize_options(self):
        """Required by Command, even though I have nothing to add."""
        pass

    def run(self):
        """The body of the command."""
        # Put something useful here!

The initialize_options and finalize_options methods are required. It's too bad distutils didn't allow them to be omitted in cases like mine where there are no options to specify. The run() method is the interesting one, that's where all the work will happen. In mine, I read the tar file distutils made, and I create a new tar file just like it, but with the permissions and owner info that I want:

    def run(self):
        """The body of the command."""
        for _, _, filename in self.distribution.dist_files:
            if filename.endswith(".tar.gz"):
                self.repack_tar(filename, "temp.tar.gz")
                shutil.move("temp.tar.gz", filename)

    def repack_tar(self, infilename, outfilename):
        """Re-pack `infilename` as `outfilename`.

        Permissions and owners are set the way we like them.

        """
        itar = tarfile.open(infilename, "r:gz")
        otar = tarfile.open(outfilename, "w:gz")
        for itarinfo in itar:
            otarinfo = otar.gettarinfo(itarinfo.name)
            if itarinfo.isfile():
                otarinfo.mode = 0644
            else:
                otarinfo.mode = 0755
            otarinfo.uid = 100
            otarinfo.gid = 100
            otarinfo.uname = "ned"
            otarinfo.gname = "coverage"
            otar.addfile(otarinfo, itar.extractfile(itarinfo))
        itar.close()
        otar.close()

To invoke my new command, I have to tell setup.py to pull it in with the --command-packages=distcmd switch. Then I can simply use "fixtar" as a command on the line just like any other:

python setup.py --command-packages=distcmd sdist --keep-temp --formats=gztar fixtar

Now I get a tar file that looks right:

drwxr-xr-x ned/coverage      0 2010-09-04 19:44 coverage-3.4b2/
-rw-r--r-- ned/coverage    516 2010-08-08 09:36 coverage-3.4b2/AUTHORS.txt
...

There's a bit more complication to it, because of the --keep-temp switch that I needed to keep the original tarred files around so they could be re-tarred. The real fixtar.py also cleans up that directory.

This was more than I wanted to do to get the right permissions in a tar file, but it was a chance to see how distutils extensions work, and it lets me make all my kits in one place.

Edward K. Ream: SQLite is serious about testing!

The How SQLite is Tested page is the most interesting discussion of software testing I have ever seen.

Mike Driscoll: Python 101: How to Open a File or Program

When I began learning Python, one of the first things I needed to know how to do was open a file. Now, the term “open a file” can mean different things depending on the context. Sometimes it means to actually open the file with Python and read from it, like with a text file. Other times, it means “to open the file in its default program”; and sometimes it means, “open the file in the program I specify”. So, when you go looking for how to do the latter two, you need to know how to ask Google just the right question or all you’ll end up with is learning how to open and read a text file.

In this article, we’re going to cover all three and we’ll also show how to open (or run) programs that are already installed on your PC. Why? Because that topic is also one of the first things I needed to learn and it uses some of the same techniques.

How to Open a Text File

Let’s start by learning how to open a file with Python. In this case, what we mean is to actually use Python to open it and not some other program. For that, we have two choices (in Python 2.x): open or file. Let’s take a look and see how it’s done!

# the open keyword opens a file in read-only mode by default
f = open("path/to/file.txt")
 
# read all the lines in the file and return them in a list
lines = f.readlines()
 
f.close()

As you can see, it’s really quite easy to open and read a text file. You can replace the “open” keyword with the “file” keyword and it will work the same. If you want to be extra explicit, you can write the open command like this instead:

f = open("path/to/file.txt", mode="r")

The “r” means to just read the file. You can also open a file in “rb” (read binary), “w” (write), “a” (append), or “wb” (write binary). Note that if you use either “w” or “wb”, Python will overwrite the file, if it exists already or create it if the file doesn’t exist.

If you want to read the file, you can use the following methods:

  • read - reads the whole file and returns the whole thing in a string
  • readline - reads the first line of the file and returns it as a string
  • readlines – reads the entire file and returns it as a list of strings

You can also read a file with a loop, like this:

f = open("path/to/file.txt")
for line in f:
    print line
f.close()

Pretty cool, huh? Python rocks! Now it’s time to take a look at how to open a file with another program.

Open a file with its own program

Python has a simple method for opening a file with its default program. It goes something like this:

import os
os.startfile(path)

Yes, it’s that easy, if you’re on Windows. If you’re on Unix or Mac, you’ll need the subprocess module or “os.system”. Of course, if you’re a real geek, then you probably have multiple programs that you might want to use to open a specific file. For example, I might want to edit my JPEG file with Picasa, Paint Shop Pro, Lightroom, Paint.NET or a plethora of other programs, but I don’t want to change my default JPEG editing program. How do we solve this with Python? We use Python’s subprocess module! Note: If you want to go old school, you can also use os.popen* or os.system, but subprocess is supposed to supersede them.

import subprocess
 
pdf = "path/to/pdf"
acrobatPath = r'C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe'
subprocess.Popen("%s %s" % (acrobatPath, pdf))

You can also write the last line like this: subprocess.Popen([acrobatPath, pdf]). Suffice it to say, using the subprocess module is also a breeze. There are many other ways to use the subprocess module, but this is one of its primary tasks. I usually use it to open a specific file (like above) or to open a program for me with specific arguments applied. I also use subprocess’s “call” method, which causes the Python script to wait for the “called” application to complete before continuing. You can also communicate with the processes that subprocess launches, if you have the know how.

Wrapping Up

As usual, Python comes through with easy ways to accomplish the tasks thrown at it. I have found very little that Python can’t handle eloquently and in an easy-to-understand way. I hope you find this helpful when you’re starting out and need to know how to open a file or program.

Further Reading

Gael Varoquaux: Scikit Learn coding sprint

We have been really crap at communicating the next scikit-learn coding sprint. It’s next week!

The coding sprint will take place the 8 and 9 September at INRIA Saclay, near Paris, in the room K110 (building K).

For those who cannot make it, it will be possible to participate using the IRC chan (#scikit-learn on irc.freenode.net).

We will start at 9am (Paris time), and a sketch of the planning can be found here. In particular:

  • More docs! we still need tutorials: features selection, model selection, cross-validation, etc..
  • Make the pipeline object really work + illustration in different contexts.
  • Clean up and doc for bayesian approaches.
  • Implementation of PCA (fit + transform).
  • FastICA (adapt the CanICA code)
  • LDA : Covariance estimators (Ledoit-Wolf) and add transform.
  • Preprocessing routines (center, standardize) with fit transform.
  • Anything that you have a particular interest in.

Do not hesitate to send on the mailing list some advices on this (incomplete…) list, and see you next week!


scikit-learn is a Python module for efficient and easy machine learning using scipy and numpy.

Nexus One : un utilisateur mécontent de la 3G poursuit Google

nexus one

Nexus One by Google

Un utilisateur mécontent de l’utilisation de la 3G sur le Nexus One veut poursuivre Google. Le téléphone aurait une fâcheuse tendance à dropper la connexion 3G quand il arrive à en accrocher une selon Nathan Nabors qui a du coup déposé une plainte en recours collectif auprès de la cour fédérale de Californie.

Nathan Nabors estime que Google l’a trompé lui et des milliers d’autres utilisateurs car il est dans l’incapacité de jouir des performances haut débit affichées dans la publicité. Et ce qui ne passe pas pour cet habitant d’Orlando, Floride, c’est l’absence totale de support de Google. De son côté Google argue de la mauvaise couverture de l’opérateur de l’utilisateur, T-Mobile. En réparation, l’accusation demande au géant américain (en plus d’un gros chèque comme c’est la pratique là bas) de « mener une campagne d’information pour informer le grand public quant au caractère illégal des pratiques de Google«  arguant que le Nexus One est impropre à l’utilisation décrite dans la publicité, et qu’il est en fait défectueux.

Possibly Related Posts:


HADOPI : Communiqué d’Éric Walter

justice Hadopi

Eric Walter, secrétaire général de la HADOPi vient tout juste d’émettre un communiqué annoncé peu avant via Twitter.

Il n’y annonce pas les premiers envois de mail tant attendus. Il était question dans ce communiqué de SOS Hadopi (que vous pouvez pour le moment suivre sur Twitter mais dont l’annonce de l’arrivée imminente du site a déjà pas mal fait buzzé), un service lancé par Renaud Veeckman, Christophe Berhault et Jérôme Bourreau-Guggenheim. La HADOPI condamne fermement ce service qu’elle taxe de commercial. SOS Hadopi entend devenir un « service d’assistance technique et juridique [...] face au délit de négligence caractérisée« . La haute autorité de son côté « met en garde les usagers contre de tels abus« . Personnellement, j’aurais apprécié une réaction identique  de la Haute Autorité devant le Failware d’Orange qui a fait rire dans le monde entier.

Tous semble bien huilé, sauif qu’il y a non pas un mais deux grains de sable :

Premier grain de sable

Renaud Veeckman a déposé la marque HADOPI avant que l’Etat ne s’en inquiète. L’affaire passera devant les tribunaux mais il serait surprenant qu’on lui en confisque l’intégralité des usages possibles malgré son antériorité faisant foi en droit des marques. Comme la HADOPI n’existait pas au moment du dépôt, on pourra difficilement plaider un trouble à l’ordre public justifiant une confiscation de la jouissance de la marque;

Second grain de sable

Depuis hier, on en sait un peu plus comment va se passer la procédure sur le terrain et surtout les suites judiciaires que l’on souhaite à tout prix éviter en cas de contestation pour laquelle il faudra jouer de pièces à convictions inaccessibles à un particulier (pour des raisons techniques ou de coût). Les experts en tout genre vont fleurir et se proposeront surement d’analyser vos trojans à la recherche de la preuve qui pourra vous disculper, ça vous coutera cher et il n’est même pas dit que les pièces soit jugées suffisantes (les difficultés d’interprétation de données informatique nécessitent un contexte pour être jugées pertinentes)… mais vous n’aviez qu’à mieux sécuriser votre ordinateur après tout. Dans ce contexte, si SOS Hadopi arrive à fédérer de vrais spécialistes, son entreprise toute commerciale soit elle trouve ici une certaine utilité.

Eric Walter, dans son communiqué souligne que la HADOPI a pour obligation légale de fournir un label pour des moyens de sécurisation. Mon ressenti est que cette labellisation est assez mal engagée et qu’elle finira par des recommandations aseptisées, même si la Haute Autorité promet que la consultation sur ce sujet délicat sera étendue. Les solutions de sécurisations n’arrêteront cependant pas le processus. Reste maintenant le dernier obstacle de la saisine du Conseil d’Etat par FDN à franchir pour que la Haute Autorité puisse travailler.

Possibly Related Posts:


Week in tech: Android tablet army begins march, Chrome, OAuth fail

Samsung fires first Android-powered salvo at iPad with Galaxy Tab: Samsung is putting the iPad in its crosshairs with its new Android-powered Galaxy Tab touchscreen tablet. The well-specced device will launch in a few week in Europe, with the US and Asia to follow soon.

Chrome 7 shows off hardware acceleration, "Tabpose": Google's Chrome Web browser will soon gain hardware-accelerated graphics—the latest trend for Web browsers that has already shown up in early builds of Internet Explorer 9 and Firefox 4.

Read the rest of this article...

Read the comments on this post


Ubuntu 10.10 Beta Released

RandyDownes sends word that Canonical has released the beta version of Ubuntu 10.10 (Maverick Meerkat). The release announcement boasts faster boot times, GNOME 2.31, and a speedier version of Evolution. In addition, "The Ubuntu Software Center has an updated look and feel, including the new 'Featured' and 'What's New' views for showcasing applications, and an improved package description view. You can now easily access your package installation history too." The release notes and download page are both available.

Read more of this story at Slashdot.


Hadopi : l’histoire de la circulaire qui circule

Numerama et PCInpact se sont fait l’écho d’une circulaire dont l’existence aurait été révélée par Sandrine Rouja (Juriscom / C-logeek). Ce document, en date du 6 août 2010 a le bon goût de répondre à une bonne partie des questions qu’on se posait sur le respect du droit à une justice équitable, l’inversion de la charge de la preuve ou du pouvoir que l’on donnait aux ayants-droit avec le petit problème de constitutionnalité que cela avait posé pour HADOPI 1. Contre toute attente, cette circulaire nous apporte une réponse claire : la supression des enquêtes de police. Oui vous avez bien compris, vous n’aurez pas le droit de vous défendre devant le juge à moins que vous ne soyez une brute épaisse en analyse forensic. Numerama relève en page 5 de la circulaire :

« dans le double objectif d’assurer la rapidité de la réponse pénale et de veiller à ce que le nouveau dispositif ne conduise à un engorgement des services de police et de gendarmerie, il conviendra d’éviter, sauf cas particulier, qu’une seconde enquête soit diligentée par ces services. »

On a ici une donnée intéressante puisqu’il est fait référence à une seconde enquête (la première étant celle de sociétés mandatées par des sociétés privées et dont personne ne s’est pour le moment intéressé aux modalités de facturation .. y a t-il des primes au rendement ?). L’enquête d’une société privée prévaudrait donc sur l’accès à une justice équitable.

Pouvait -il en être autrement ?

Non ! Clairement non… Vous croyez que le législateur s’est cassé la tête à inverser la charge de la preuve pour voir s’engorger les tribunaux d’enquêtes techniques pouvant être onéreuses. Prouver qu’une infraction a été commise par un tiers et par l’intermédiaire d’un cheval de Troie non détecté par l’anti-virus de Madame Michu pourtant installé par son petit fils, ingénieur informaticien, sur un Windows cracké …

Comme on le craignait donc depuis le début, il ne va pas être aisé de se défendre devant la HADOPI. C’est d’autant plus révoltant qu’on a ici la démonstration parfaite d’une inversion de la charge de la preuve, doublée d’une obligation de sécurisation de l’accès Internet pour lequel on nage toujours dans une étonnante « subtilité ». Plus inquiétant encore, on a ici une splendide et élégante manière de contourner l’avi du Conseil Constitutionnel qui observait il y a un peu plus d’un an que « seul un juge pouvait décider de la coupure d’un accès Internet car l’accès au Net est aujourd’hui une composante de la liberté d’information et de la communication« .

Alors oui … la HADOPI va peut-être commencer à faire peur. On arrive bien dans la phase répressive promise… jusque là tout va bien.

Mais une société privée qui se substitue à l’autorité judiciaire, quand on a encore les débats parlementaire en tête sur cette question, c’est particulièrement irritant… et là, je suis tout irrité.

Possibly Related Posts:


Dave Beazley: Using telnet to access my Superboard II (via Python and cassette ports)

Welcome to part 3 of my "Superboard II" trilogy. For the first two parts, see these posts:


Dave's Superboard II

First, a brief digression.

Why Bother?

Aside from the obvious nostalgia (the Superboard II being my first computer), why bother messing around with something like this? After all, we're talking about a long-since-dead 1970s technology. Any sort of practical application certainly seems far-fetched.

The simple answer is that doing this sort of thing is fun--fun for the same reasons I got into programming in the first place. When my family first got the Superboard, it was this magical device--a device where you could command it to do anything you wanted. You could write programs to make it play games. Or, more importantly, you could command it to do your math homework. Not only that, everything about the machine was open. It came with electrical schematics and memory maps. You could directly input hex 6502 opcodes. There were no rules at all. Although writing a game or doing your homework might be an end goal, the real fun was the process of figuring out how to do those things (to be honest, I think I learned much more about math by writing programs to do my math homework than I ever did by actually doing the homework, but that's a different story).

Flash forward about 30 years and I'm now doing most of my coding in Python. However, Python (and most other dynamic languages) embody everything that was great about my old Superboard II. For instance, the instant gratification of using the interactive interpreter to try things out. Or, the complete freedom to do almost anything you want in a program (first-class functions, duck-typing, metaprogramming, etc.). Or, the ability to dig deep into the bowels of your system (ctypes, Swig, etc.). Frankly, it's all great fun. It's what programming should be about. Clearly the designers of more "serious" languages (especially those designed for the "enterprise") never had anything like a Superboard.

Anyways, getting back to my motivations, I don't really have any urgent need to access my Superboard from my Mac. I'm mostly just interested in the problem of how I would do it. The fun is all in the process of figuring it out.

Back to the Superboard Cassette Ports

Getting back to topic, you will recall that in my prior posts, I was interested in the problem of encoding and decoding the audio stream transmitted from the cassette input and output ports on my Superboard II. In part, this was due to the fact that those are the only available I/O ports--forget about USB, Firewire, Ethernet, RS-232, or a parallel port. Nope, cassette audio is all there is.

From the two parts, I wrote some Python scripts that encode and decode the cassette audio data to and from WAV files. Although that is somewhat interesting, working with WAV files was never my real goal. Instead, what I really wanted to do was to set up a real-time bidirectional data communication channel between my Mac and the Superboard II. Simply stated, I wanted to create the equivalent of a network connection using the cassette ports. Would it even be possible? Who knows?

So far as I know, the cassette ports on the Superboard were never intended for this purpose. Although there are commands to save a program and to load a program, driving both the cassette input and output simultaneously isn't something you would do. It didn't even make any sense. There certainly weren't any Superboard commands to do that.

Building a Soft-Modem Using PyAudio

To perform real-time communications, the Superboard needs to be connected to both the audio line-out and line-in ports of my Mac. Using those connections, I would then need to write a program that operates as a soft-modem. This program would simultaneously read and transmit audio data by encoding or decoding it as appropriate (see my past posts).

I've never written a program for manipulating audio on my Mac, but after some searching, I found the PyAudio extension that seemed to provide the exact set of features I needed.

To create a soft-modem, I defined reader and writer threads as follows:

# Note : This is Python 2 due to the PyAudio dependency.
import pyaudio
import kcs_decode      # See prior posts
import kcs_encode      # See prior posts
from Queue import Queue

FORMAT    = pyaudio.paInt8
CHANNELS  = 1
RATE      = 9600
CHUNKSIZE = 1024

# Buffered data received and waiting to transmit
audio_write_buffer = Queue()
audio_read_buffer = Queue()

# Generate a sequence representing sign change bits on the real-time
# audio stream (needed as input for decoding)
def generate_sign_change_bits(stream):
    previous = 0
    while True:
        frames = stream.read(CHUNKSIZE)
        if not frames:
            break
        msbytes = bytearray(frames)
        # Emit a stream of sign-change bits
        for byte in msbytes:
            signbit = byte & 0x80
            yield 1 if (signbit ^ previous) else 0
            previous = signbit

# Thread that reads and decodes KCS audio input
def audio_reader():
    print("Reader starting")
    p = pyaudio.PyAudio()
    stream = p.open(format = FORMAT,
                    channels = CHANNELS,
                    rate = RATE,
                    input=True,
                    frames_per_buffer=CHUNKSIZE)

    bits = generate_sign_change_bits(stream)
    byte_stream = kcs_decode.generate_bytes(bits, RATE)
    for b in byte_stream:
        audio_read_buffer.put(chr(b))

# Thread that writes KCS audio data
def audio_writer():
    print("Writer starting")
    p = pyaudio.PyAudio()
    stream = p.open(format = FORMAT,
                    channels = CHANNELS,
                    rate = RATE,
                    output=True)
    while True:
        if not audio_write_buffer.empty():
            msg = kcs_encode.kcs_encode_byte(ord(audio_write_buffer.get()))
            stream.write(buffer(msg))
        else:
            stream.write(buffer(kcs_encode.one_pulse))

if __name__ == '__main__':
    import threading

    # Launch the reader/writer threads
    reader_thr = threading.Thread(target=audio_reader)
    reader_thr.daemon = True
    reader_thr.name = "Reader"
    reader_thr.start()

    writer_thr = threading.Thread(target=audio_writer)
    writer_thr.daemon = True
    writer_thr.name = "Writer"
    writer_thr.start()    

The operation of this code is relatively straightforward. There is a reader thread that constantly samples audio on the line-in port and decodes it into bytes which are stored in a queue for later consumption. There is a writer thread that encodes and transmits outgoing data (if any). If there is no data, the writer transmits a constant carrier tone on the line out (a 2400 Hz wave).

These threads operate entirely in the background. To read data from the Superboard, you simply check the contents of the audio read buffer. To send data to the Superboard, you simply append outgoing data to the audio write buffer.

Creating a Network Server

To tie all of this together, you can now write a network server that connects the real-time audio streams to a network socket. This can be done by defining a third thread like this:

import socket
import time

def server(addr):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
    s.bind(addr)
    s.listen(1)
    print("Server running on", addr)
    # Wait for the client to connect
    while True:
        c,a = s.accept()
        print("Got connection",a)
        c.setblocking(False)
        try:
            # Enter a loop where we try to transmit data back and forth between the client and the audio stream
            while True:
                # Check for incoming data
                try:
                    indata = c.recv(8192)
                    if not indata:
                        raise EOFError()
                    indata = indata.replace(b'\r',b'\r' + b'\x00'*20)
                    for b in indata:
                        audio_write_buffer.put(b)
                except socket.error:
                    pass
                # Check if there is any outgoing data to transmit (try to send it all)
                if not audio_read_buffer.empty():
                    while not audio_read_buffer.empty():
                        b = audio_read_buffer.get()
                        c.send(b)
                else:
                    # Sleep briefly if nothing is going on.  This is fine, the max
                    # data transfer rate of the Superboard is 300 baud
                    time.sleep(0.01)
        except EOFError:
            print("Connection closed")
            c.close()

if __name__ == '__main__':
    import threading

    # Launch the reader/writer threads
    ... see above code ..

    # Launch the network server
    server_thr = threading.Thread(target=server,args=(("",15000),))
    server_thr.daemon = True
    server_thr.name = "Server"
    server_thr.start()

    # Have the main thread do something (so Ctrl-C works)
    while True:
            time.sleep(1)

This server operates as a simple polling loop over a client socket and the incoming audio data stream. Data received on the socket is placed in the write buffer used by the audio writer thread. Data received by the audio reader is send back to the client. This code could probably be cleaned up through the use of the select() call, but I frankly don't know if select() works with PyAudio and didn't investigate it. Given that the maximum data rate of the Superboard is 300 baud, a "good enough" solution seemed to be just that.

Putting it to the Test

Now, the ultimate test--does it actually work? To try it out, you first have to launch the above audio server process. For example:

bash % python audioserv.py
Reader starting
Writer starting
Server running on ('', 15000)

Next, make sure the Superboard II is plugged into the line-in and line-out ports on my Mac. On the Superboard, I had to manually type two POKE statements to make it send all output to the cassette output and to read all keyboard input from the cassette input.

POKE 517, 128
POKE 515, 128

Finally, use the telnet command to connect to the audio server.

bash $ telnet localhost 15000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
^]
telnet> mode character
LIST

OK
PRINT "HELLO WORLD"
HELLO WORLD

OK

Excellent! It seems to be working. It's a little hard to appreciate with just a screenshot. Therefore, you can check out the following movie that shows it all in action:

Again, it's important to emphasize that there is no other connection between the two machines other than a pair of audio cables.

That is all (for now)

Well, there you have it--using Python to implement a soft-modem that encodes/decodes cassette audio data in real-time, allowing me to remotely access my old Superboard using telnet. At last, I can write old Microsoft Basic 1.0 programs from the comfort of my Aeron chair and a 23-inch LCD display--and there's nothing old-school about that!

Hope you enjoyed this series of posts. Sadly, it's now time to get back to some "real work." Of course, if you'd like to see all of this in person, you should sign up for one of my Python courses.

Michele Simionato: What's new in plac 0.7

plac is much more than a command-line arguments parser. You can use it to implement interactive interpreters (both on a local machine on a remote server) as well as batch interpreters. It features a doctest-like mode, the ability to launch commands in parallel, and more. And it is easy to use too!

Ubuntu 10.10 beta arrives with new netbook UI

Canonical has announced the availability of the Ubuntu 10.10 beta release. The new version of the popular Linux distribution, codenamed Maverick Meerkat, is scheduled for final release in October. It brings some noteworthy user interface improvements and updated software.

The beta ships with GNOME 2.31, which introduces support for the new dconf configuration storage system. Ubuntu's standard F-Spot photo tool has been replaced by Shotwell, a relatively new application that is developed by nonprofit software group Yorba. Although it's not as feature-complete as F-Spot, it's progressing quickly and has a lot to offer.

Canonical has continued its work on panel indicators, especially the audio indicator which now has playback controls in addition to a volume management slider. This will eliminate the need for individual audio applications to have their own notification area icons.

Work has also continued on the Ubuntu Software Center, which now promotes "Featured" applications and has a section for purchasing commercial third-party applications. The look and feel of the Software Center is more refined and aesthetically sophisticated.

The Ubuntu Netbook Edition has seen particularly dramatic improvements during this development cycle due to Canonical's work on the new Unity user interface. Unity, which was initially introduced in May, has matured very rapidly. It has a global menubar that works surprisingly well.

Users who want to get an early look at the new version can download the beta release from the Ubuntu website. For additional information, you can refer to the release notes.

Read the comments on this post


Google sticks Wave in a box, puts a bow on top

Contrary to popular belief, Google Wave is not quite dead. Google plans to expand upon the open source code it has already released to form a more complete, standalone application known as "Wave in a Box." Wave will work (or not work, depending on how you look at it) as it always has, but with the new app, developers can run their own wave servers and host waves from their own machines.

"Since the beginning, it has been our vision that the Google Wave protocols could support a new generation of communication and collaboration tools," wrote Wave software engineer Alex North on the Google Wave Developer Blog. "The response from the developer community to date has been amazing and rewarding. Even more so now, we believe that developers and other projects are a critical part of this story."

North says the project will include an app bundle with both a Wave server and client, a "fast and fully-featured" wave panel in the Web client, persistent wave store and search for the server, and the ability to import wave data from the Web. Additionally, it will have gadget, robot, and data API support, as well as the ability to federate across other Wave in a Box instances. Even more details are available in Google's Wave Protocol Forum.

Google announced earlier this week that the Web version of Wave would remain online through "at least" the end of the year, and that users would be able to export their waves during that time. It was a blip of good news to those few lamenting Wave's short lifespan, but Wave in a Box should be a major step toward helping the project live on.

Read the comments on this post


PyCharm: Django development with PyCharm: new video on new JetBrains TV

We’ve just announced a new JetBrains TV site yesterday and already adding new content to it about PyCharm IDE: Django development with PyCharm.

The short 5-min video gives a brief overview of main features starting from Django project creation to a first start in the browser. Also, the demo shows many coding productivity features of PyCharm editor, e.g. code completion for Python, inside Django templates and for HTML tags; live templates/snippets; surround with…; and examples of PyCharm intentions such as automatic creation of view method and a template.

Check out the new Django development with PyCharm screencast.

Watch and develop with pleasure!
The JetBrains Team

Mike Driscoll: Pyowa – September 2010 Wrap-Up

This is for all you Pyowa home-boys out there what missed our gathering. We don’t know why you homebodies didn’t come and hang out and talk shop wit us, but we think you really truly missed out on our phat gathering. We had around 10 real homies show up to hear the jibber jabber about South, a Django data migration tool. We were supposed to hear about SWIG too, but ended up swigging pop (or soda for you southerners) and chowing down on free pizza instead.

Next time, we’ll be booking it at the Ames Public Library in (you guessed it!) Ames, IA on Thursday, October 7th. If you think you got the chops for talking about Python, drop me a line and I’ll hook you up.

Isotoma: Scaffolding template tags for Django forms

We love Django here at Isotoma, and we love using Django’s awesome form classes to generate self-generating, self-validating, [X]HTML forms.

However, in practically every new Django project I find myself doing the same thing over and over again (and I know others do too): breaking the display of a Django form instance up into individual fields, with appropriate mark-up wrappers.

Effectively I keep recreating the output of BaseForm.as_p/as_ul/as_table with template tags and mark-up.

For example, outputting a login form, rather than doing:

{{ form.as_p }}

We would do:

<p>
{% if form.username.errors %}
  {% for error in form.username.errors %}
    {{ error }}
  {% endfor %}
{% endif %}
{{ form.username.label }} {{ form.username }}
</p>
<p>
{% if form.password.errors %}
  {% for error in form.password.errors %}
    {{ error }}
  {% endfor %}
{% endif %}
{{ form.password.label }} {{ form.password }}
</p>

Why would you want to do this? There are several reasons, but generally it’s to apply custom mark-up to a particular element (notice I said mark-up, not styling, that can be done with the generated field IDs), as well as completely customising the output of the form (using <div>’s instead etc.), and also because some designers tend to prefer this way of looking at a template.

“But”, you might say, “Django already creates all this for us with the handy as_p/as_ul/as_table methods, can you just take the ouput from that?”
Well, yes, in fact on a project a couple of weeks ago that’s exactly what I did, outputting as_p in a template, and then editing the source chucked out in a browser.
Which gave me the idea to create a simple little tool to do this for me, but with the Django template tags for dynamically outputting the field labels and fields themselves.

I created django-form-scaffold to do just this, and now I can do this from a Python shell:

>>> from dfs import scaffold
>>> from MyProject.MyApp.forms import MyForm
>>> form = MyForm()
>>> # We can pass either an instance of our form class
>>> # or the class itself, but better to pass an instance.
>>> print scaffold.as_p(form)

{% if form.email.errors %}{% for error in form.email.errors %}
{{ error }}{% endfor %}{% endif %}
<p>{{ form.email.label }} {{ form.email }}</p>
{% if form.password1.errors %}{% for error in form.password1.errors %}
{{ error }}{% endfor %}{% endif %}
<p&gtl{{ form.password1.label }} {{ form.password1 }}</p>
{% if form.password2.errors %}{% for error in form.password2.errors %}
{{ error }}{% endfor %}{% endif %}
<p>{{ form.password2.label }} {{ form.password2 }}</p>

Copy and paste this into a template, tweak, and Robert’s your mother’s brother.

As well as as_p(), the dfs.scaffold module also has the equivalent functions as_ul(), as_table, and an extra as_div() function.

La voie de l'autodidacte (2/2)

La suite du précédent…

Investissement personnel

(4.1)

rz0

Le public pas si général que ça associe souvent l’image du programmeur autodidacte à la culture geek. Et beaucoup de jeunes techno-enthousiastes se mettent en tête d’apprendre à programmer.

Vous reconnaissez-vous dans cette image ? Je ne vais pas nier que nous sommes tous plus ou moins geek (dans le sens où nous apprécions des usages de l’informatique un peu marginaux), mais l’étiez-vous avant de programmer ? Si oui, cela a-t-il été un facteur dans votre décision de commencer à apprendre en autodidacte ?

alp

Non je n’étais pas vraiment à fond dans l’informatique « grand public » avant d’attaquer la programmation au tout début de chez tout début. Je me reconnais dans geek selon la définition qu’on donne à ce mot. Je suis passionné par des domaines de l’informatique tout comme je le suis par beaucoup de domaines en mathématiques, ou en science en général. Et si geek est considéré ici comme désignant une personne qui est tellement passionnée qu’elle peut passer des heures et des heures, coupée du reste, à apprendre des choses, pratiquer, etc, alors oui. Dans tous les cas, non ça na pas été un facteur dans ma décision de commencer à apprendre la programmation en autodidacte. C’est vraiment la curiosité intellectuelle qui m’y a poussé.

bluestorm

Je pense que j’étais effectivement déjà curieux du fonctionnement des ordinateurs avant de commencer à programmer. Mais je ne connaissais pas du tout la culture geek à l’époque, qui n’a jamais été une motivation et dans laquelle je ne me reconnais toujours pas. Quand j’ai commencé la programmation, je considérais cette activité comme un jeu de l’esprit basé sur l’abstraction, un peu comme des mathématiques très appliquées, et pas du tout un outil pour créer des jeux vidéos, faire des blagues à ses amis ou pirater l’ordinateur de son voisin…

rz0

Pour ma part, ce n’était pas vraiment le cas. Je jouais un peu, je bidouillais trois fois rien pour avoir un beau fond d’écran et un thème Windows sympa, mais voilà tout. Geeker en venu après, au fur et à mesure que j’apprenais à mieux comprendre l’informatique.

Je trouve cela même quelque peu dangereux que l’amalgame soit si facile. Généralement, je n’aime pas que l’on me confonde avec le mec qui est au courant des derniers gadgets à la mode, suis l’actualité vulgarisée de tous les domaines possibles et imaginables de l’informatique, et possède sa carte de membre au parti^Wfanclub Apple/Google/Microsoft/etc. du coin. Cependant, pour le novice, apprendre à programmer pour se sentir plus geek est une motivation initiale comme une autre, que je ne critique pas ; mais je ne pense pas non plus qu’elle puisse demeurer la raison maîtresse qui continuera à guider l’apprentissage. Si elle ne laisse pas place à des objectifs plus sérieux, l’investissement ne sera pas au rendez-vous, et avec lui le niveau…

(4.2)

rz0

Revenons sur l’investissement. C’est une question difficile. Combien d’heures, de jours, de mois, faut-il consacrer à son apprentissage, et avec quel rythme, pour espérer devenir « bon » ? Je doute que quiconque ici ait la prétention de pouvoir apporter une réponse définitive à cette question.

En revanche, je peux répondre à la suivante : quel investissement m’a-t-il fallu pour arriver là où je suis aujourd’hui ? Si l’on s’en réfère à la fameuse règle des 10000 heures, je dois avoir fait mon quota. Est-ce que cela fait de moi un expert ? Faut voir. Avec la définition toute relative que certains ont de « maîtriser quelque chose » (en particulier sur les CV), je suis certainement un expert en pas mal de choses. :D Blague à part, je dirais simplement que la clef est certainement de pratiquer, et continuer à s’auto-former, régulièrement, année après année…

Qu’en est-il de votre expérience ?

alp

Je dois avoir mon quota aussi… Si l’on veut sérieusement connaître et « maîtriser » un langage, une technologie, une théorie, peu importe, il faut y consacrer beaucoup de temps. Qu’il s’agisse d’apprendre les bases, des les consolider, ou d’attaquer des choses plus avancées, et ce en théorie comme en pratique, cela demande toujours beaucoup de temps. Si l’on est pas prêt à passer beaucoup de temps sur quelque chose, autant laisser tomber l’idée de pouvoir vraiment bien connaître et savoir utiliser le « quelque chose » en question. Pour illustrer, imaginez combien de caps j’ai franchi entre le moment où j’ai appris à déclarer un int en C++ et le moment où j’ai commencé à savoir faire de la métaprogrammation vraiment sérieuse, toujours en C++… Donc oui, il faut persévérer, refuser de ne pas comprendre, être prêt à s’investir autant que nécessaire. Note : cela n’empêche toutefois pas d’avoir une vie sociale, il s’agit de savoir gérer son temps et d’être capable de se motiver lorsque l’on a du temps à consacrer à l’apprentissage.

bluestorm

J’ai tendance à estimer grossièrement trois niveau de connaissance : ce que je n’arrive pas à faire, ce que je sais faire, et ce que je sais expliquer aux autres. Je ne sais pas si transmettre aux autres suffit pour être « bon » dans un domaine, mais personnellement ça me suffit ; ce qui est sûr c’est que ça demande pas mal de pratique, et assez (mais surtout pas trop !) de confiance en ses compétences.

Pour couvrir un domaine aussi large que la programmation, il faut sans doute effectivement une ou plusieurs heures par jour, pendant des années. Après, c’est un apprentissage progressif, il y a des choses qu’on arrive à faire rapidement, et d’autres qui peuvent résister très longtemps. J’ai encore beaucoup à apprendre et je trouve ça excitant.

(4.3)

rz0

Un autre acteur que l’on retrouve souvent dans les discussions autour de l’apprentissage de la programmation en autodidacte est le logiciel libre. Faut-il s’investir dans le logiciel libre pour réussir sa formation d’autodidacte ? Quels gains ? Quelles contraintes ?

alp

Au début : aucun intérêt. Je dirais que le meilleur moment c’est quand on est à la phase 3 (cf. dans les premières questions) car on est capable d’apporter du bon code tout en en apprenant nous-même. Contribuer aux logiciels libres vous en apprend bien plus humainement que techniquement, pour peu que votre niveau soit assez élevé. De toute manière, avant d’en arriver à pouvoir contribuer à un logiciel libre, il faut avoir réalisé des projets personnels plus sérieux qu’un petit morpion, par exemple. Mais c’est une expérience intéressante et enrichissante que de participer à un projet libre, car vous vous familiariserez avec les outils entourant les logiciels libres (subversion/git/darcs/mercurial/autres pour le versionning, mailing lists, bug tracker, etc.) et apprendrez la collaboration à échelle plus ou moins grande. Donc non il ne faut pas nécessairement s’y investir, mais ce n’est pas une mauvaise chose et si vous en avez l’occasion cela s’avèrera probablement enrichissant.

bluestorm

Pour moi, aimer la programmation conduit naturellement à un soutien du logiciel libre. Une fois qu’on réalise que le code source est essentiellement une façon de transmettre des idées, on est conduit à souhaiter que ces idées soient distribuables, réutilisables et améliorables.

Le logiciel libre est aussi une chance pour celui qui veut apprendre à programmer : cela fait plein de code déjà écrit qui n’attend que d’être lu et compris. On apprend beaucoup en regardant comment font les autres, beaucoup plus qu’en se contentant de répéter les mêmes pratiques personnelles.

Ce qui est aussi essentiel à mon avis, c’est rencontrer une critique de ce que l’on fait. Demander des commentaires aux autres, les inciter à juger notre travail. Les communautés de logiciel libre sont de bons endroits pour le faire, mais cela peut aussi se faire ailleurs.

rz0

Ma contribution au libre est très récente et quasi inexistante, aussi, je n’ai pas grand chose à dire sur le sujet. Tout ce que je peux remarquer, c’est qu’elle ne m’a pas été nécessaire pour en arriver où je suis ; avec de la volonté et des idées, je considère qu’il est tout aussi productif de se fixer de petits projets à soi.

Technique

(5.1)

rz0

Pour démarrer avec les questions techniques, parlons de langages de programmation. Quels sont vos langages de prédilection ? Depuis combien de temps les pratiquez-vous ? Qu’est-ce qui a arrêté votre choix ? Envisagez-vous d’en changer bientôt ?

alp

Les deux langages que j’utilise vraiment souvent et couramment sont C++ et Haskell. Je pratique le C++ depuis mes 15 ans, ce qui fait donc six ans environ. Concernant Haskell, je le pratique depuis un peu plus d’un an à peine, mais très intensivement. Je suis resté sur C++ car bien que considéré comme complexe, il s’avère offrir une énorme puissance lorsque l’on combine les paradigmes, ce qui permet d’écrire du code assez bas-niveau avec une certaine abstraction, par exemple. Bref, en C++ on peut vraiment aller dans la direction que l’on veut, il suffit de savoir comment le faire, et c’est ce que j’ai appris avec les années et de très bonnes ressources. Concernant le Haskell, c’est principalement l’élégance et la communauté qui m’ont séduit. Beaucoup de bibliothèques/outils, le tout avec une façon de penser totalement fonctionnelle, et bien d’autres features qui m’ont plu. Plus j’en fais, plus j’en apprends, et plus je suis content de mon choix. Après toutes ces années à m’intéresser à pleins de langages, je pense que je tiens mon duo de choc et je n’envisage vraiment pas d’en changer.

bluestorm

J’utilise encore principalement OCaml. Entre le moment où j’ai appris OCaml pour faire de l’algorithmique, et la période où je me suis fixé en OCaml pour l’ensemble de mes besoins en programmation, j’ai fait des essais avec d’autres langages plus populaires (C, PHP), pour voir du pays. Plus tard, j’ai aussi appris progressivement le Haskell, qui est un langage très intéressant et qui serait un choix raisonnable, mais je trouve OCaml plus pratique comme langage généraliste : c’est un bon compromis entre l’élégance des langages fonctionnels statiquement typés et la simplicité à l’exécution.

J’aime bien lire du code même dans les langages que je ne connais pas ou très mal, et modifier des programmes pour les adapter à mes besoins. Il m’arrive donc occasionellement de toucher à du code Python, ELisp, PHP, des scripts shell, etc. Ce ne sont pas des langages de prédilection, mais parfois il faut faire des efforts pour se coordonner avec les autres. Il y a aussi les langages intéressants à apprendre, mais que je ne pratique pas du tout : Erlang, Prolog, Oz..

Je n’envisage pas de changer bientôt de langage principal, mais il y a des langages que je voudrais avoir le temps de découvrir (Scala, Forth, ATS) et j’aimerais faire plus de Coq. Tous les langages ont des défauts, et je pense qu’on peut faire mieux que ce qui existe : je changerai certainement de langage à long terme.

rz0

Pour ma part, le C m’a bien servi durant ces huit–neuf dernières années, et je n’ai pas tellement l’intention de le remplacer maintenant. Cependant, je cherche toujours un langage de script pour complémenter mon usage. Le script shell devient vite maladroit ; pour l’heure, je n’ai rien trouvé à mon goût…

(5.2)

rz0

Parlons un peu du parcours qui vous a mené à vos choix actuels : Par quels langages êtes-vous passés avant d’aboutir à votre outillage actuel ? À quel point avez-vous commencé à incorporer l’algorithmique dans votre apprentissage ? Et l’usage des outils (débogueur, gestionnaire de versions, etc.) ? Quelle place pour le génie logiciel ? Enfin, conseilleriez-vous aux débutants de suivre la même voie ?

alp

Dans l’ordre plus ou moins chronologique : Visual Basic, C, C++, HTML, PHP, CSS, Javascript, Java, Prolog, Python, OCaml, Haskell ; ce sont les langages auxquels j’ai vraiment touché un minimum. J’ai quelques connaissances en assembleur, (Emacs) Lisp, Pascal, etc. mais rien qui ne mérite vraiment d’être mentionné.

J’ai incorporé l’algorithmique assez tôt. Cela vient principalement du fait que j’ai toujours bien aimé les maths et j’ai donc assez tôt voulu résoudre des problèmes de maths avec des programmes, et il se trouvait que par enchantement mes algos était un cas particulier d’un algo plus connu, etc. Par contre, mon apprentissage structuré et solide de l’algorithmique est arrivé bien après. Et je suis d’ailleurs loin d’être un as dans le domaine, je vais régulièrement voir mon Cormen pour lire ou relire des passages. Le débogueur est arrivé quand j’ai commencé à faire des trucs non triviaux en C++ et que j’avais des bugs « mystiques » comme il nous arrive tous d’en avoir et que l’on n’arrive pas à résoudre à coups de std::cout << "Je suis dans MaClasse::MaFonctionMembre()", std::cout << "Je rentre dans cette fonction et tel et tel trucs valent ceci et cela" et j’en passe. Donc bien au bout d’un an et demi ou deux ans. Les gestionnaires de versions, wouah, là c’est carrément bien plus tard. J’ai dû commencer au bout de quatre ans environ, quand j’ai pour la première fois travaillé sur un projet avec d’autres personnes dans un cadre plus ou moins sérieux. Bref, cela ne fait pas si longtemps que « j’utilise des outils de grands ».

En ce qui concerne le génie logiciel, disons que c’est à mes yeux pas mal attaché à l’aspect « business » du développement, qui m’a beaucoup rebuté. Rares sont les situations où cela s’avère particulièrement pertinent selon moi de s’attacher à 400% au génie logiciel tel qu’il est pratiqué. En ayant pas mal investi le monde de la programmation fonctionnelle, je me rends compte que ce n’est pas « le design OO », les « schémas UML » ou autres qui comptent, mais la réflexion sur l’interface que l’on offre, dans un sens général. Bien sûr, on a un vocabulaire spécifique pour chaque paradigme, mais finalement ce n’est pas tant différent et il y a une majeure partie de la réflexion en amont qui demeure la même, et je trouve justement que dans le monde du « business » de l’informatique, on met tout ça de côté. Donc oui, je connais un minimum tout ça, mais non je n’ai pas tellement introduit ça dans mes projets, dans le sens « commun » de l’expression « génie logiciel ».

Enfin, j’ai un parcours similaire à bien des gens, dans le sens où j’ai pas mal vadrouillé entre les langages et paradigmes de programmation, j’ai lu des bouquins, articles, cours, tutoriels, howtos, etc. et chaque étape j’ai été amené à découvrir un nouveau langage, des techniques, des points de vue, des raisonnements, et je recommande tout simplement de se laisser « guider » comme cela, car au bout d’un certain temps de toute façon cela se stabilisera. Suivre le même parcours que moi précisément n’aurait pas vraiment de sens, car c’est ce qu’il m’est arrivé par rapport à mon expérience, aux choix que j’ai faits, etc.

bluestorm

J’ai longtemps erré sur le chemin de la programmation web (XHTML, PHP, SQL…), avant de me rendre compte que ça ne me plaisait pas. Je pense que ce qui la rend si tentante, c’est la facilité à montrer ce qu’on fait aux autres. Je me suis cependant rendu compte au bout d’un moment que ce n’était pas un environnement agréable pour programmer, entre autres à cause de la domination de mauvais outils (PHP) et de l’importance de normes à absorber avant de pouvoir faire les choses bien. Ça a l’air simple de loin, mais coder un parseur XML complet est une tâche quasiment insurmontable.

J’ai toujours incorporé l’algorithmique dans mes considérations. Je pense que j’ai mis un peu de temps avant que ça devienne vraiment naturel (sans doute un an ou deux). Il s’agit seulement des bases : quand on approfondit le sujet, l’algorithmique est un domaine extrêment technique qui ne m’intéresse en fait pas énormément.

Pour l’usage des outils, je suis extrêment paresseux et en pratique assez minimaliste et réactionnaire. Je n’ai jamais appris à utiliser un débugguer par exemple, tout simplement par flemme, et je débuggue mes programmes en ajoutant des instructions d’affichage aux bons endroits. Jusqu’à récemment, je faisais aussi très peu de tests. Pour programmer j’utilise un éditeur de texte et les outils de base de mon langage, pas d’environnements trop lourds et complexes.

Je suis par contre fortement convaincu par les gestionnaires de versions : j’ai fait l’expérience plusieurs fois du code qui « était juste il y a une heure, mais il ne marche plus du tout et je n’arrive plus à le refaire marcher », et on comprend vite l’intérêt de faire des sauvegardes régulières, et surtout expliquées, de son travail ; c’est encore plus utile quand il y a plusieurs auteurs.

J’attache beaucoup d’importance au fait de découper l’évolution du code en modifications atomique, que j’essaie de bien expliquer. On ne peut pas toujours avoir ce qu’on veut (parfois on est pressé et on n’a pas le temps de soigner cet aspect autant qu’il le faudrait), mais je crois que ça a globalement une influence positive sur la façon dont on organise les modifications de son programme.

Je m’intéresse au génie logiciel, mais j’ai parfois du mal à faire la différence entre le bon sens, les conseils de grand-mère, les choses carrément trompeuses et les idées nouvelles et intéressantes. Je pense qu’il y a beaucoup de choses à apprendre dans cette direction, mais je préfère les domaines plus formalisés, où il est plus facile de séparer l’important de l’accessoire.

Aux débutants, je conseillerais de commencer avec des outils simples, qu’ils comprennent bien, et de passer progressivement à des choses plus complètes dans les domaines qui les intéressent.

rz0

Je suis passé par le Turbo Pascal, puis je suis tombé directement sur le C, qui me suivra, à partir de là. Bien sûr, j’ai flirté avec bon nombre d’autres langages et de technologies, à partir de là. J’ai failli faire de C++ mon outil principal, et j’ai fait pas mal d’assembleur x86 également.

L’algorithmique un minimum non triviale n’est pas venue avant un bon nombre d’années, deux ou trois peut-être. Je crois que c’est autour de la Seconde que j’ai mis la main sur un Knuth (que je n’ai jamais réussi à digérer :) et un Cormen (bien plus comestible, mais j’en ai laissé des bouts…), et voilà… Et si je me suis spécialisé dans mon domaine, ce qui vaut aussi pour l’algorithmique associée, j’en apprends encore beaucoup, notamment en cours, à l’école ! Héhé, et oui, pas en autodidacte cette fois-ci…

Il en est un peu de même pour outils : cela ne m’est pas venu non plus avant bien deux ans dans l’obscurité, à déboguer à coup de printf… ça forge le caractère, dira-t-on. :p

Quant à savoir si je conseillerais le même parcours, c’est difficile à dire. Je pense que la voie de l’autodidacte est constituée d’une part non négligeable de hasard, et je pense que cet aléa fait partie de l’apprentissage : apprendre à se débrouiller, à faire la part des choses, entre ce que l’on doit savoir, et ce que l’on veut maîtriser.

Conclusion

(6.1)

rz0

L’interview touche maintenant à sa fin. Pour conclure, un mini-quizz !

  1. Les trois plus importantes qualités d’un autodidacte ?
  2. Le plus grand piège à éviter quand on débute ?
  3. Le bon âge pour commencer ?
  4. Livre ou cours sur Internet ?
  5. Algorithmique avant langage, langage avant algorithmique, ou les deux en même temps ?
alp
  1. Curiosité intellectuelle, persévérance et être débrouillard(e).
  2. Ne pas faire face aux problèmes rencontrés (faire faire par quelqu’un d’autre, etc).
  3. Fin du collège, lycée.
  4. Livre si possible !
  5. Un peu de langage, de quoi pouvoir implémenter les algos de base, avant d’apprendre l’algo, et ensuite apprendre les deux en parallèle.
bluestorm
  1. Curiosité, persévérance, rigueur.
  2. Se laisser entraîner vers des choses pénibles ou fastidieuses par
    envie de plaire aux autres.
  3. N’importe quand, tant qu’on est vraiment intéressé.
  4. Les deux : comparer les différentes sources.
  5. En même temps. Pratique et théorie.

rz0
  1. Curiosité intellectuelle, ténacité, résistance (à l’échec, aux conflits, au ridicule, etc. :-°).
  2. Sombrer dans la justification de l’improductivité.
  3. Collège ou lycée, quand on n’a rien à faire de ses journées.
  4. Ça dépend si on est pauvre…
  5. Langage avant algorithmique, pour moi… pas trop avant non plus, mais histoire d’avoir un truc avec lequel appliquer, quand on attaque l’algorithmique.

(6.2)

rz0

Un dernier mot pour vos fans ? ;)

alp

Comme le dit dangerous, et tous ceux qui le connaissent le reconnaîtront bien là, « Y’a pas de secret, faut bosser ! ».

bluestorm

J’espère ne pas avoir de fans ; pour programmer, les idées sont plus importantes que les gens.

Pete Hunt: Announcement: PyMySQL 0.3

I’m proud to announce the release of PyMySQL 0.3. For those of you unfamiliar with PyMySQL, it is a pure-Python drop-in replacement for MySQLdb with an emphasis on compatibility with MySQLdb and for various Python implementations. I started working on the project due to my frustrations stemming from getting MySQLdb working on Snow Leopard. PyMySQL has been tested on CPython 2.3+, Jython, IronPython and PyPy, and we have an unreleased Python 3.0 branch in Subversion. I encourage anyone hoping to connect to MySQL from Python to check it out and report any bugs you might find! Our current focus has been bringing it up to compatibility with SQLAlchemy and Django, and we have by and large achieved that goal with a high level of performance.

Check it out at http://www.pymysql.org/.

Vinay Sajip: Using a custom file naming scheme for rotated log files

When you use rotated log files with Python logging's built-in functionality, the rotated files are named by appending a number to the base log file name: thus, app.log would give rise to log files app.log, app.log.1, app.log.2 etc.

Sometimes, you may not want this: for example, you may want to preserve the file extension so that you can take advantage of file associations (typically on Windows). You can implement a scheme where log file names take the form app.log, app.1.log, app.2.log etc. by subclassing RotatingFileHandler and overriding the doRollover() method. The exact code for this method varies slightly across different versions of Python, so I won't reproduce the whole method, but there's always an if statement in the method which does the rotation. In your overridden method, you can use the following logic (in place of the default logic) to implement an extension-preserving rotation scheme, for example as follows:

if self.backupCount > 0:
name, ext = os.path.splitext(self.baseFilename)
for i in range(self.backupCount - 1, 0, -1):
sfn = "%s.%d%s" % (name, i, ext)
dfn = "%s.%d%s" % (name, i + 1, ext)
if os.path.exists(sfn):
if os.path.exists(dfn):
os.remove(dfn)
os.rename(sfn, dfn)
dfn = "%s.1%s" % (name, ext)
if os.path.exists(dfn):
os.remove(dfn)
os.rename(self.baseFilename, dfn)

Chrome reaches second birthday, version 6 goes stable

When Google launched its Chrome Web browser in 2008, it was clear that the product had considerable potential. Its emphasis on performance and its intriguing minimalistic user interface attracted a lot of well-deserved attention. Today, exactly two years later, Chrome has over 80 million users, a 7.52 percent global market share (21.87 at Ars, making it the second most popular browser here behind Firefox), and is gradually creeping into the mainstream.

It wasn't entirely clear at first if the browser would have real staying power or if it would be cast aside unfinished like so many of Google's other ambitious *cough*Wave*cough* experiments. But Google's commitment hasn't waned, and it's increasingly evident that the browser is an important part of Google's platform strategy and long-term aspirations for the future of the Web. To mark Chrome's second anniversary, Google has announced the official release of Chrome 6, a new major stable version of the browser.

Read the rest of this article...

Read the comments on this post