Planet Python
Last update: May 16, 2012 08:47 AM
May 16, 2012
eGenix is pleased to announce eGenix pyOpenSSL Distribution 0.13.0-1.0.0j for Python 2.4 - 2.7, with support for Windows, Linux and Mac OS X.
May 16, 2012 07:00 AM
and come experience the wonderful talks from our keynotes and speakers at Singapore!
May 16, 2012 05:03 AM
May 15, 2012
English only!
I have not stopped working on Nikola, my static site generator. Here are the plans:
- Finish the theme installer (so you can get a theme from the site easily)
- Implement a theme gallery on the site (same purpose)
- Fix a couple of bugs
- Update manual
- Polish a few theme bits
- Release version 3.x (new major number because it requires manual migration)
After that, I will push on projects Shoreham (hosted sites) and Smiljan (planet generator)
and make them more public. Shoreham will become a real web app for those who don't want
to have their own server. For free, hopefully!
Once I have that, I have no further feature ideas, really. So I need more people to start
using it, and that means I have to start announcing it more.
So, stay tuned for version 3.x sometime next week.
Post-Nikola, I will do a rst2pdf release, and then will get back to work on a book.
May 15, 2012 10:05 PM
It makes now more than 2.5 years since the first release of series 1.4.
This ends the maintenance on this series.
To anyone who is still using it, it is highly recommended to upgrade to a more recent series.
May 15, 2012 08:56 PM
Site Section:
Keywords:
SciPy and Numpy are great packages for scientific computing.
Unfortunately, installation on Mac OS X 10.7 Lion is not a very smooth affair.
It can be a pain for moderately-experienced developers, and a nightmare for novice end-users.
The problem is compounded by the fact that both SciPy and Numpy, as well other components of a scientific computing stack that depend on them, such as matplotlib or pymc, all need to be built using the same compiler suite, build flags and architecture.
This would be fine if the pre-built distribution packages available through "easy_install" or "pip" for these various components were indeed all mutually compatible, or if "easy_install"/"pip" were smart enough to pick the correct packages for one's particular system.
But, at least the last time I tried the "easy_install" route, this is not the case.
Numpy installed fine via "easy_install".
But SciPy failed miserably half-way through.
Which meant that I had to build SciPy myself, which I finally did after some irritating false starts.
Then I tried "easy_install"-ing PyMC.
This apparently worked, in that the install procedure yielded no obvious errors.
But this was misleading.
Actually trying to import the module failed due to architectural incompatibilities.
So, after various false starts, I finally got three packages (SciPy, Numpy, and PyMC) installed and working (so far) on my system.
The following are the steps that I took.
Prerequisites
Download and install the following (installing Apple Developer Tools should give you Git):
- Apple Developer Tools
- Git
- gfortran
Build Environment
Set up the build environment by setting the following environmental variables in your session shell:
export CC=clang
export CXX=clang
export FFLAGS=-ff2c
export LDFLAGS="-arch x86_64 -Wall -undefined dynamic_lookup -bundle"
export FFLAGS="-arch x86_64"
This is the key to successfully setting up the stack.
If you add other packages that depend in some way on either SciPy or Numpy in the future, you need to make sure the above environmental variables are set in your build session shell when building/installing them.
Numpy
Download the Numpy source from:
http://sourceforge.net/projects/numpy/files/NumPy/
Unpack, build and install it:
tar xf numpy-1.6.1.tar.gz
cd numpy-1.6.1
python setup.py build
python setup.py install
SciPy
Clone the SciPy source repository:
git clone https://github.com/scipy/scipy.git
Build and install:
cd scipy
python setup.py build
python setup.py install
PyMC
Download the PyMC source from:
http://pypi.python.org/pypi/pymc/
Unpack, build, and install:
tar xf pymc-2.2.tar.gz
cd pymc
python setup.py build
python setup.py install
May 15, 2012 02:37 PM
A couple months ago I briefly reviewed Machine Learning for Hackers by Drew Conway and John Myles White. Today I’m looking at Machine Learning in Action by Peter Harrington and comparing the two books.
Both books are about the same size and cover many of the same topics. One difference between the two books is choice of programming language: ML for Hackers uses R for its examples, ML in Action uses Python.
ML in Action doesn’t lean heavily on Python libraries. It mostly implements its algorithms from scratch, with a little help from NumPy for linear algebra, but it does not use ML libraries such as scikit-learn. It sometimes uses Matplotlib for plotting and uses Tkinter for building a simple GUI in one chapter. The final chapter introduces Hadoop and Amazon Web Services.
ML for Hackers is a little more of a general introduction to machine learning. ML in Action contains a brief introduction to machine learning in general, but quickly moves on to specific algorithms. ML for Hackers spends a good number of pages discussing data cleaning. ML in Action starts with clean data in order to spend more time on algorithms.
ML in Action takes 8 of the top 10 algorithms in machine learning (as selected by this paper) and organizes around these algorithms. (The two algorithms out of the top 1o that didn’t make it into ML in Action were PageRank, because it has been covered well elsewhere, and EM, because its explanation requires too much mathematics.) The algorithms come first in ML in Action, illustrations second. ML for Hackers puts more emphasis on its examples and reads a bit more like a story. ML in Action reads a little more like a reference book.


http://www.johndcook.com/blog/2008/06/27/wine-beer-and-statistics/#comment-170809
May 15, 2012 01:23 PM
In my previous post I wrote about the advantages of using the BatchWriteItem functionality in DynamoDB. As it turns out, I was overly optimistic when I wrote my initial code: I only called the batch_write_item method of the layer2 module in boto once.
The problem with this approach is that many of the batched inserts can fail, and in practice this happens quite frequently, probably because of transient network errors. The correct approach is to inspect the response object returned by batch_write_item -- here is an example of such an object:
{'Responses': {'mytable': {'ConsumedCapacityUnits': 5.0}},
'UnprocessedItems': {'mytable': [
{'PutRequest': {'Item': {'mykey': 'key1', 'myvalue': 'value1'}}},
{'PutRequest': {'Item': {'mykey': 'key2', 'myvalue': 'value2'}}},
{'PutRequest': {'Item': {'mykey': 'key3', 'myvalue': 'value3'}}}]}}
You need to look for the value corresponding to the 'UnprocessedItems' key. This value is a dictionary keyed by the name of the table you're inserting items in. The value corresponding to that key gives you a list of other dictionaries with keys corresponding to the operations you applied to the table ('PutRequest' in my case). Going one level deeper allows you to finally obtain the attributes (keys + values) of the items that failed, which you can then try to re-insert.
So basically you need to stay in a loop and keep calling batch_write_items until UnprocessedItems corresponds to an empty list. Here is a
gist containing code that reads a log file in lzop format, looks for lines containing a key + white space + a value, then inserts items based on those key/value pairs into a DynamoDB table. I've been pretty happy with this approach.
Before I finish, I'd like to reiterate the gripe I have about the static nature of determining your Read and Write Throughput when dealing with DynamoDB. I understand that it makes life easier for AWS in terms of the capacity planning they have to do on their end to scale the table across multiple instances, but it's a black art when it comes to capacity planning you need to do as a user. You almost always end up overcommitting as a DynamoDB user, and it's hard to make sense sometimes of the capacity units you're consuming, especially when doing inserts of large volumes of data.
May 15, 2012 11:22 AM
I've been programming Python for a good while, and in the beginning I was very occupied with the style in which things are written.
I always advocated using_names_like_this for everything, I guess because it is easy to read and understand, and it also takes into account acronyms which should be uppercase, as these acronyms are also separated from other words, for_example_html_text.
However, over the years, mostly these last couple of years, naming conventions aren't that important any more. Python is a very flexible language, and one can for example create a function that returns an instance of a class, the class being decided by the invoked function.. With this flexibility, separating functions from classes is somewhat redundant IMO, and one might just as well do everything in lower-case separated by an underscore.
However, I'm not riding these arguments anymore, there are a number of different Python systems such as Zope, Django, Repoze, Archetypes, Plone etc. that use a myriad of different ways of naming things.
I think the most important thing is, and has always been, the proper use of tabs and spaces in Python files, as this is the thing that can get you and has real impact on the "flow" of the program.
I think there are a couple of times in my Python career that I've encountered bugs due to mixed and erroneous spacing, and at least one of those bugs was pretty tough to get, but it's been a good while since that one. I don't think much about spacing any more, Emacs does the right thing whether I'm in text or Python mode.
One snag that always seems to get me is the use of commas in complex schema definitions in Archetypes for example, but that's thankfully always an error that stops the entire system so it's easy to catch.
My argument? Naming conventions aren't that important because there will never be enough willpower and resources to make everything completely consistent in the Python ecosystem.. and if one is very preoccupied with naming conventions, maybe it is time to drink a little less coffee, stress a little less and focus on the important parts of a program. [:)
May 15, 2012 09:16 AM
It is very common having to add some feature only for the super users in our website, and it is common that the site where we put this feature is the admin site. Normally we try to hide from the user that he is (programmatically) outside of the Django adiministration, to provide for a better user experience; so our view will have the same path prefix as the administration (/admin/), and the same styles.
If we use forms in these features, we have a layout problem, or mucho work with CSS, because Django renders the forms (as_p, as_ul, as_table) in a very different way compared to the admin site. The django-form-admin app is tailored to solve this problem.
To show the diferences in layout between a normal form and another that uses django-form-admin, we’ll show an example of a form to update the value of some cookies defined in the settings.
For this we will create the following view, in for /admin/edit-cookies/:
@permission_required('my_perm')
def edit_cookies(request):
initial = {}
data = None
if request.method == 'POST':
data = request.POST
for cookie in settings.COOKIES_EDITABLES:
initial[cookie] = request.COOKIES.get(cookie, None)
form = ChangeCookie(settings.COOKIES_EDITABLES,
initial=initial, data=data)
if form.is_valid():
messages.info(request, _('Added the cookies'))
response = HttpResponseRedirect(reverse('edit_cookies'))
form.save(response)
return response
return render_to_response('foo/edit_cookies.html',
{'form': form},
context_instance=RequestContext(request))
We now code a form, to create/modify/delete the cookies:
class ChangeCookie(forms.Form):
def __init__(self, cookies, *args, **kwargs):
for cookie in cookies:
self.base_fields[cookie] = forms.CharField(required=False)
super(ChangeCookie, self).__init__(*args, **kwargs)
def save(self, response):
for key, val in self.cleaned_data.items():
if val:
response.set_cookie(key, smart_str(val))
else:
response.delete_cookie(key)
And the template to be rendered by our view, edit_cookies.html:
{% extends "admin/base_site.html" %}
{% load i18n admin_static admin_modify %}
{% block extrahead %}
{{ block.super }}
{{ media }}
{{ form.media }}
{% endblock %}
{% block extrastyle %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />
{% endblock %}
{% block coltype %}
{% if ordered_objects %}colMS{% else %}colM{% endif %}
{% endblock %}
{% block breadcrumbs %}
{% endblock %}
{% block content %}
<div id="content-main">
<form action="." method="POST">
{% csrf_token %}
{{ form }}
<div>
<input type="submit" name="submit" value="{% trans "Update Cookies" %}"/>
</div>
</form>
</div>
{% endblock %}
The end result is not very good, because Django renders the forms in a very different way in the admin site.

But if we install the django-form-admin application in out project and we add some like this in our form (there are many ways to do it: inheritance, delegation, implicit, explicit) the difference is more than considerable:
def __unicode__(self):
from formadmin.forms import as_django_admin
return as_django_admin(self)

This app has only had a minimal change in the last year, so this is a stable version. No changes were needed to adapt it to Django 1.3 or Django 1.4.
I hope you like it.
Related Posts:
May 15, 2012 09:02 AM
It's not a state secret that I like ZODB . It's a very
civilized way to store web application data. I'll try to enumerate some of
the most important reasons I like ZODB here, and why I prefer it to other
NoSQL systems and relational systems.
For the record, the stuff in this blog post is in the context of writing a
web application. I don't mean it in the context of an OLAP system, or some
data warehousing system. I mean it in the context of writing your typical
web application, which needs to support fewer than a couple thousand requests
per second, a small fraction of which are write requests.
Transactions
ZODB uses transactions. When you write to a ZODB database, you change a
bunch of objects, then you commit the changes. Until you commit your
changes, other threads and processes accessing the database won't see those
changes.
I take transactions entirely for granted when writing an application.
Wrapping a set of actions which mutate persistent data in a transaction makes
a whole class of really hard
problems
disappear. Many existing NoSQL databases like MongoDB do not.
Any speed or feature benefit in using a non-transactional data store would
just be lost in the noise of needing to cope with the loss of
transactionality for anything except the most immense, purpose-built
application (e.g. you're writing Twitter, or GitHub). If an application is
anticipated to serve fewer than, say, 50 write requests per second or so,
it's pretty foolish to even momentarily consider using a system without
transactions. Even much busier systems can be engineered to use databases
with transactions, albeit with lots of fancy coding.
Truth be told, I'm really not clever enough to write a system without
transactions where I needed to have any level of confidence that I have the
storage of inter-related data right. I'm also pretty sure I don't want to be
that clever, and that a job that required me to be that clever would be a
very long job indeed. I certainly wouldn't willingly reach into my toolbox
and pick out a data storage without transactions for a run-of-the-mill,
low-traffic web application.
ZODB gives me transactions, and I appreciate
that.
Caching
The way ZODB operates is pretty simple. Any pickleable object created in
memory can be persisted. It's persisted by attaching it (via
``__setattr__``) to any other persistent object. Once persisted, every
object has its own identifier that can be used as a cache key.
Because the organization of data in the database is a function of the same
data as it might otherwise be organized in memory, ZODB has a natural caching
system that is simple and robust. Each persistent object, once loaded,
remains in a per-thread memory cache until evicted. It's evicted when it
hasn't been accessed in a while and RAM is needed to load a more recently
accessed object into the cache, or when another thread or process has changed
the object. There's very little cost associated with asking for the same set
of objects over and over once that set of objects has been asked for
initially.
If your working set is smaller than your available RAM, the way ZODB caches
its objects effectively means that accessing an object loaded from ZODB is
almost costless after the object is first loaded. That object won't be
evicted from the in-memory cache until it changes. In such cases, your
application will work at "RAM speed" rather than at "disk speed". If your
working set is larger than available RAM, accessing the same set of objects
over and over won't be costless, but if you ask for that set of objects often
enough, and they don't change very often, and you have an appropriate amount
of memory in the machine, they will almost never be evicted from the cache.
Because most requests in a typical web application are read requests (they do
not mutate persistent data), this built-in caching is extremely effective in
a real-world sense. You usually don't have to employ a third-party caching
system to make pages render quickly. They just render quickly in the first
place without degrading too much as load increases. There are certainly
times you have to think harder about it, such as when you begin to have too
much data in your working set to effectively fit into the cache, but often
applications never reach this level of exposure, and when they do, the answer
is often to just increase the memory in the system and the cache size. In
the worst case scenario, you do what everyone else who doesn't use ZODB does:
you use a global external cache to make lookup speeds acceptable. In ten
years of ZODB use, I can count the number of times I've had to do this on one
finger. These days, instead of using an external cache, I might just try to
change ZODB instead and improve its caching.
Testability
Of the things I really like about ZODB, the one I like the most is the
ability to write easily unit-testable code.
I like the majority of the tests I write to be unit tests. Note: unit
tests. Not functional tests. Not integration tests. I just want to test
the code I'm trying to test, not its integration with the rest of the system.
Functional and integration tests are useful and important too, and you need
them for any serious application, but you can get better coverage and a much
faster set of tests if you use unit testing in the majority. I don't think
most people know what the difference between these styles of testing mean.
But if you do know, you really know, and you care.
I have a deep respect for the amount of effort put into making
object-relational mappings work. SQLAlchemy and other such systems are well
written and thoughtfully executed. However, I find it unappealing that every
ORM system I've run across effectively requires that you write integration
and/or functional tests to actually test the code in your application. These
tests need the code to run against a real database. The test code actually
causes data to be modified in that database. Between each test case, the
database needs to be reset to a baseline state.
This, in practice, utterly blows. As a limitation, it seems to be, at least
in part, a function of the query syntax exposed by the ORM. It's an awful
hard syntax to mock out. To my knowledge, it's so hard that no one has even
tried, and folks just cave and use a "real" database, and write all of their
tests as functional tests, or at least they write all of the tests that come
near the database as functional tests. Most real-world code comes near the
database, so it's often diminishing returns to even attempt to discern which
of the tests can be non-integration tests, and thus people tend to just use
the same setup and teardown for all their tests, even the ones that don't
come close to the database.
Unit tests run much, much, much faster than integration and functional tests.
When I see blog posts where people are trying to parallelize their test runs
across multiple machines because their test suite takes so long to run, I
want to weep, because it's very likely that they'd get just as much of a
sense of comfort from a set of unit tests that ran thousands of times faster
with a few functional and integration tests thrown in for the sake of sanity.
But they can't, because their toolchain doesn't really support it.
ZODB makes it very easy to write the majority of your tests as unit tests.
Because the object graph is just a tree of Python objects, and because each
of those objects can be instantiated without any particular root or parent,
and because often the "query syntax" of ZODB is just plain old Python item or
attribute access, you can often just write test code like this:
class TestFile(unittest.TestCase):
def _makeOne(self, stream, mimetype):
from .. import File
return File(stream, mimetype)
def test_ctor_no_stream(self):
inst = self._makeOne(None, None)
self.assertEqual(inst.mimetype, 'application/octet-stream')
def test_ctor_with_stream_mimetype_None(self):
stream = StringIO.StringIO('abc')
inst = self._makeOne(stream, None)
self.assertEqual(inst.mimetype, 'application/octet-stream')
fp = inst.blob.open('r')
fp.seek(0)
self.assertEqual(fp.read(), 'abc')
The above test tests an implementation of a ZODB object representing a file
(using the ZODB "blob" functionality). The file object it's testing would be
considered a "model" by most people used to "MVC" terminology. Model code is
actually pretty easy to test, and I suspect that with careful factoring and
stubbing it's possible to test most ORM model code without actually using a
database connection.
Let's try something harder. The hardest code to test in any web application
is view code. View code is the code that responds to an invocation of a
particular URL within your system. It's the code that ties everything
together: the model objects that represent persistent storage, the various
functional subsystems of the application like the HTTP request, sessions,
mailers and filesystems, etc. It's hard to test because it's "where the
rubber meets the road". Consider the following Pyramid view function, which
is taken from an application that uses ZODB:
from myapp import File
def add_file(context, request):
appstruct = get_appstruct(request)
name = appstruct['name']
filedata = appstruct['file']
stream = None
filename = None
if filedata:
filename = filedata['filename']
stream = filedata['fp']
if stream:
stream.seek(0)
else:
stream = None
name = name or filename
fileob = request.registry.content.create(File, stream)
context[name] = fileob
return HTTPFound(request.mgmt_path(fileob, '@@properties'))
The above view function accepts a context object (a ZODB object representing
a "folder", in this case, which is just a container of other ZODB objects),
and a request object. It returns a Response. Here's a test for the function
in the case where there's no file data provided:
import unittest
from pyramid import testing
class Test_add_file(unittest.TestCase):
def test_no_filedata(self):
from .. import add_file
created = testing.DummyResource()
context = testing.DummyResource()
request = testing.DummyRequest()
request.mgmt_path = lambda *arg: '/mgmt'
request.registry.content = DummyContent(created)
appstruct = {'name':'abc', 'file':None}
request.appstruct = appstruct
result = add_file(context, request)
self.assertEqual(result.location, '/mgmt')
self.assertEqual(context['abc'], created)
class DummyContent(object):
def __init__(self, result):
self.result = result
def create(self, *arg, **kw):
return self.result
Note that the test creates "dummy" (aka stub) objects for the context, the
request, and the object that is returned from the call to create. It
asserts that the created object is added to the context under the name abc.
And that's all it does. In the running application, when a new file object
is created by the view, it is persisted. But in the test, no database setup
is required because the "query API" is limited to a single call:
__setitem__, which seats the object into its parent. We can mock this up
without much of a problem. In this case, the DummyResource has a suitable
__setitem__ already, so we didn't need to do any mocking (it was already
done for us). This test will run in microseconds.
There are definitely far more complex cases, requiring more stubbing, such as
code that uses an indexing and querying system like repoze.catalog to look
up persistent objects efficiently by asking a centralized index for all
objects with such-and-such attribute. In those cases, the "query API" is not
nearly as simple. But it's still simple enough to mock up without ever
requiring a "real" ZODB database connection. The tests get longer, and the
mocking and stubbing code becomes more complex. But it's not hopeless, like
it seems to be in ORM systems.
Comparable idiomatic ORM code would construct the file object the same way
but would then tend to call e.g. add on a semimagical threadlocal "session"
object. So you'd need to at least mock out the thread local session, or come
up with some other context-sensitive way to get at the session without the
thread-local. It would also need to ensure that the a file object with the
same name didn't already exist in the database before adding it blindly,
which would imply some sort of exists query. Something like this (I realize
my syntax is likely terrible):
from myapp import Session
from myapp import File
def add_file(request):
appstruct = get_appstruct(request)
name = appstruct['name']
filedata = appstruct['file']
stream = None
filename = None
if filedata:
filename = filedata['filename']
stream = filedata['fp']
if stream:
stream.seek(0)
else:
stream = None
name = name or filename
exists = Session.query(File).filter_by(name=name).one()
if exists:
Session.query(File).delete(name=name)
fileob = request.registry.content.create(File, stream)
Session.add(fileob)
return HTTPFound(request.mgmt_path(fileob, '@@properties'))
A test is nowhere near as straightforward to write when the view looks like
this. You've obtained a global Session object from an import that needs to
either be mocked or a stub of it passed in specially. This is purely
convention, and you could construct a system that passed the session in like
the "context" in a ZODB app, so that's not really a deep concern. But still,
the contract of the Session object is complex. It needs to support a query
method that accepts an argument, the result of which needs to support both a
filter_by and delete method. The filter_by method needs to return an
object that has a one method, and so on. The session is the source of
truth in this view, and so mutations done through it need to be reflected in
later queries.
This example doesn't even take into account more common cases where one query
depends on the result of another data-mutating query, or methods of the
session like flush which add attributes to recently add -ed objects
representing automatically computed primary keys and so on.
It's no wonder that no one bothers to try to mock it out, and just punts back
to always testing functionally. When you test functionally, your test runs
in milliseconds rather than microseconds. And that difference adds up across
lots of tests. You get a lot of power from the ORM, especially the power to
do very ad-hoc queries in a sort of stream-of-consciousness way which is very
useful in highly dynamic, ill-defined web applications. But you're paying a
price. And often you don't need the ad-hocness supplied by the query syntax.
You know exactly what you're looking for and where to find it. ZODB lends
itself well to such applications, and the complexity curve seems more
adjustable on a per-view basis.
For what it's worth I'd love to be wrong about needing to always write
functional tests when an ORM is used. It would mean I could write
applications that use an ORM in a style that suits my historical application
writing patterns, and in a style that supports very fast test suites. Let me
know if you've tried and succeeded. In the meantime, I much prefer to write
ZODB applications for testing purposes. Note that it's not just ORMs that
have this issue; database bindings for other NoSQL databases have similar
issues (e.g. PyMongo); their APIs are very complicated and are difficult to
mock. Often the features you gain from that complexity is not worth the
price you pay.
May 15, 2012 07:10 AM
In our previous blog post dedicated to Python and Java, we saw how Maven can orchestrate a unified build process for these two languages.
But most of the time, all artifacts within a build should take the same version. It was not the case in the sample project of our previous blog post, so let's find a way to unify this.
For Java it's easy: JARs and WARs are using the version located in their respective POMs, 0.1 in this case:
com.shiningpanda
jsample
0.1
jar
It would be great if Python projects could also get their versions from the POM. Let's see how to do that.
The POM version has to be propagated when calling
setup.py. The easiest way is to set an environment variable with
exec-maven-plugin. Modify
setuptools/pom.xml in the sample project as follows:
org.codehaus.mojo
exec-maven-plugin
${project.version}
Now a
VERSION environment variable containing the value of the POM's
version tag is available for
setup.py. It can be used to generate a
__version__ module containing the project's version. The
setup.py script of the
pysample project would be modified like this:
# Folder containing setup.py
root = os.path.dirname(os.path.abspath(__file__))
# Path to __version__ module
version_file = os.path.join(root, 'pysample', '__version__.py')
# Check if this is a source distribution.
# If not create the __version__ module containing the version
if not os.path.exists(os.path.join(root, 'PKG-INFO')):
fd = codecs.open(version_file, 'w', 'utf-8')
fd.write('version = %r\n' % os.getenv('VERSION', '?'))
fd.close()
# Load version
exec(open(version_file).read())
# Setup
setup(
name = 'pysample',
version = version,
packages = find_packages(),
)
Note that we only generate the
__version__ module if the
PKG-INFO file does not exist. Indeed, an existing
PKG-INFO file means that we're installing a source distribution previously generated by the
setup.py sdist command.
Now all our artifacts are getting their version number from their POM. The versions in the POMs are easily handled thanks to the
maven-release-plugin, but we will cover this in another blog post.
A Maven convention wants that version numbers are postfixed with a
-SNAPSHOT between two releases. Setuptools uses more likely a
.dev one, so feel free to process your POM version in your
setup.py, for instance with:
os.getenv('VERSION', '?').replace('-SNAPSHOT', '.dev')
It can also be useful to get the revision version from your source code management tool. To do so, use the
buildnumber-maven-plugin. Following the same principle, export an environment variable containing the revision that can be used in the
setup.py to compute an artifact version (with a
0.1.dev-r1989 or
0.1.dev-rb0c1c6 pattern for example).
In addition to a
Hosted Continuous Integration Service, ShiningPanda is also offering build and release management expertise, so if you have questions or if you are stuck with your internal build process do not hesitate to contact our
service team!
May 15, 2012 05:48 AM
The second event in our series of Distutils2 sprints was again a success. We’ve managed to fix some interesting issues and we’ve gained some experience points at dealing with the black magic of the packaging arcane.
We would like to thank TP1 for hosting the sprint at their nice Downtown Montreal offices and also for the pizza. Pierre Paul, our host, wrote a longer post relating the event.
Stay tuned for upcoming announcements on Distutils2 sprints.
Special thanks to the sprinters:
- Julien Courteau
- Jonathan Fernandes
- Patrice Gauthier
- Mathieu Leduc-Hamel
- Pierre Paul Lefebvre
- Alex Parij
- Kim Pettersen
Stay tuned this week for the announcement of the next sprint.
Here’s a glimpse of patches being born:

Divine inspiration:

May 15, 2012 01:48 AM
Pythonistas
The last workshop in French for the winter 2012 season is this Wednesday. We wish to remind you that there is still plenty of places left, and, especially, that the room we have for the workshop is not SH-R810 as announced, but SH-2420, also in the Sherbrooke Pavillion of UQÀM.
Here are all the details:
Django : monter une application web en Python
May 15, 2012 12:48 AM
May 14, 2012
You should go to DjangoCon Europe in lovely Zurich, Switzerland. Here are 10 reasons why:
1. Chocolate
So much of what we like about chocolate comes from Switzerland. For example, Milk Chocolate was invented in Switzerland.
2. Keynote speaker: Jacob Kaplan-Moss
Always a great speaker and fun to be around, he's one of the BDFL's of Django.
3. Cheese
I grew up thinking that Swiss Cheese was just about holes. It's so much more. I can't wait to try fresh European cheese made by master craftsmen from the freshest ingredients.
4. Keynote speaker: Jessica McKellar
In a word, Jessica is incredible. She's a Twisted core developer, PSF board member, part of the trio responsible for the gigantic Boston Python User Group's massive size explosion, and a talented speaker. She's used her incredible talents and skills to increase diversity in the community and generally help other people.
5. Breakfast
Muesli was invented in Switzerland. I love Muesli. I was floored by how much better it was in New Zealand. I can't wait to try it in it's homeland.
6. Web Site
The DjangoCon Europe site is crazy. I mean, look at all those animations!
7. Talks
This is a single track event with proven speakers like Zachary Voase and Andrew Godwin, yet balances that with bringing in new blood to spice things up. And dare I say I'm giving a technical talk with Audrey Roy? ;-)
8. Mountains
With all the incredible food, you would think you would gain umpteen kilograms. Fortunately there are mountains all around to climb and hike.
9. Sprints
Want to sprint on Django itself? Look no further because there will be Django core developers around! There will also be notable Python developers like Kenneth Reitz and others around working hard on a lot of different projects. It's going to intense and fun!
10. Castles
Living in the USA, we just don't have anything like castles. DjangoCon Europe will be near a small horde of stone fortifications. Which means if the Zombie Apocalypse happens during the conference, we'll have many secure places to go. They also make lovely tourist destinations. :-)
What are you waiting for?
DjangoCon Europe has a cap on attendance. Tickets for Python events have been selling out, not just for PyCon US. Don't miss out!
It's all about me
Yup.
Call me selfish but I want you there because I haven't haven't met all our European friends yet in person. Hope to see you next month in Zurich!
May 14, 2012 07:30 PM
May 14, 2012 06:50 PM
Contributing to Open Source can be stressful.
By opening a Pull Request to a popular project, you're inviting the maintainers and all of their users to analyze and scrutinize your code. Often, they will.
Most of the time, the maintainers of the projects do their best to be kind. If they have feedback or criticism, it's generally positive. Unfortunately, this isn't always the case.
Every once in while, maintainers and community members will shun and insult a contributor's work. This is a perfect example of what you should never do.
What if the Pull Request in question was the person's first time ever contributing to a project? They could be scared away from the world of open source forever.
Instead of simply yelling at a potential contributor and causing a mess of negativity and stress; the maintainer should take the opportunity to educate the user. They should point the user to a guide that outlines what the proper protocol for his project is.
As a project maintainer, it's extremely important to be respectful to your contributors. They often take what you say very personally.
Publishing Open Source
I don't handle stress and negativity well at all. I almost instantly get a terrible headache, have difficulty concentrating, lose my appetite, and my general quality of life degrades almost immediately.
There's a difference between being stressed and being in a stressful situation. One can be caught in a tremendously stressful situation and not be stressed at all with the right mixture of perspective and empathy.
By publishing your code (or anything, really) on the open internet, you're inviting the whole world to analyze and scrutinize it, line by line. That takes guts. People may love it, hate it, disagree with your general approach, or be convinced that you're doing their community a huge disservice. That can be stressful.
Don't worry about non-constructive feedback. It serves no purpose. Realize that some people just take things way too seriously. Tell them to be on their way.
Listen to everyone, then disregard it.
—311
Reflect
Take some time to reflect. Remember why you're doing this in the first place. I write open source software because I love software and want to help make my world a better place.
Why are you? If you don't have answer, maybe you shouldn't be doing it. If you find yourself maintaining a project purely out of obligation, maybe you should be doing less.
Before you tweet, comment on a pull request, or comment publically about a project, remember that it's often not a peice of code you're critiquing — it's a human being.
I don't have the energy or patience for non-constructive feedback. Be cordial and positive or be on your way.
May 14, 2012 10:00 AM
A few weeks ago, I pinged my peeps on #twisted asking why the banner for a custom SSH server wasn't rendering properly. After some digging around and some inconsistent results (well, consistently bad results for me), we weren't able to resolve anything, and I had to set the problem aside.
The SymptomThe first thing I had tried was subclassing
Manhole from
twisted.conch.manhole, overriding (and up-calling)
connectionMade, writing the banner to the terminal upon successful connection. This didn't work, so I then tried overriding
initializeScreen by subclassing
twisted.conch.recvline.RecvLine. Also a no-go. And by "didn't work" here's what I mean:
In both Linux (Ubuntu 12.04 LTS, gnome-terminal) and Mac (OS X 10.6.8, Terminal.app), after a successful login to the Twisted SSH server, the following sequence would occur:
- an interactive Python prompt was rendered, e.g., ":>>"
- the banner was getting written to the terminal, and
- the terminal screen refreshed with the prompt at the top
This all happened so quickly, that I usually never even saw #1 and #2. Just the second ":>>" prompt from #3. Only by scrolling up the terminal buffer would I see that the banner had actually been rendered. Even though I was doing my terminal.write after connectionMade and initializeScreen, it didn't seem to matter.
Discovery!Some time last week, I put together example Twisted plugins showing what the problem was, and the circumstances under which a banner simply didn't get rendered. The idea was that I would provide some bare-bones test cases that demonstrated where the problem was occurring, post them to IRC or the Twisted mail list, and we could finally get it resolved. 'Cause, ya know, I really want my banners ...
While tweaking the second Twisted plugin example, I finally poked my head into the right method and discovered the issue. Here's what's happening:
- twisted.conch.recvline.RecvLine.connectionMade calls t.c.recvline.RecvLine.initializeScreen
- t.c.recvline.RecvLine.initializeScreen does a terminal.reset, writes the prompt, and then switches to insert mode. But this is a red herring. Since something after initializeScreen is causing the problem, we really need to be asking "who's calling connectionMade?"
- t.c.manhole_ssh.TerminalSession.openShell is what kicks it off when it calls the transportFactory (which is really TerminalSessionTransport)
- openShell takes one parameter, proto -- this is very important :-)
- openShell instantiates TerminalSessionTransport
- TerminalSessionTransport does one more thing after calling the makeConnection method on an insults.ServerProtocol instance (the one I had tried overriding without success), and as such, this is the prime suspect for what was preventing the banner from being properly displayed: it calls chainedProtocol.terminalProtocol.terminalSize
- chainedProtocol is an insults.ServerProtocol instance, and its terminalProtocol attribute is set when ServerProtocol.connectionMade is called.
- A quick check reveals that terminalProtocol is none other than the proto parameter passed to openShell.
But what
is proto? Some debugging (and the fact that of the three
terminalSize methods in all of twisted, only one is an actual implementation) reveals that
proto is a
RecvLine instance. Reading that method uncovers the culprit in our whodunnit: the first thing the method does is call
terminal.eraseDisplay.
Bingo! (And this is what I was referring to above when I said "poked my head" ...)
Since this was called after all of my attempts to display a banner using both
connectionMade and
initializeScreen, there's no way my efforts would have succeeded.
Here's What You DoHow do you get around this? Easy! Subclass :-)
The class
TerminalSessionTransport in
t.c.manhole_ssh is the bad boy that calls
terminalSize (which calls
eraseDisplay). It's the last thing that
TerminalSessionTransport does in its
__init__, so if we subclass it, and render our banner at the end of our
__init__, we should be golden. And we are :-)
You can see an example of this
here.
Not sure if this sort of thing is better off in projects that make use of Twisted, or if it would be worth while to add this feature to Twisted itself. Time (and blog comments) will tell.
EpilogueAs is evident from the screenshot above (and the link), this feature is part of the
DreamSSH project. There are a handful of other nifty features/shortcuts that I have implemented in DreamSSH (plus some cool ones that are coming) and I'm using them in projects that need a custom SSH server. I released the
first version of DreamSSH last night, and there's a pretty clear README on the github project page.
One of the niftier things I did last night in preparation for the release was to dig into Twisted plugins and override some behaviour there. In order to make sure that the conveniences I had provided for devs with the Makefile were available for anyone who had DreamSSH installed, I added subcommands... but if the service was already running, these would fail. How to work around that (and other Twisted plugin tidbits) are probably best saved for another post, though :-)
May 14, 2012 10:39 AM
So you know a little bit about programming (perhaps you’ve read the free book, “Invent Your Own Computer Games with Python”, a free programming book for beginners whose author shamelessly plugs at every chance) but you want to get better at coding. You can’t seem to find any open source projects that are at your level or easy for new people to contribute to. You’ve gone through a few of the practice problems at Project Euler but you want to create something more substantial, or at least a cool thing you can show your friends. (Not that finding the 31337th prime number isn’t cool.)
Here’s a list of game clone ideas for you to implement. Each has a short description of the game, links to videos of the game, and descriptions of what kind of algorithms you’ll need to know in order to implement them. These games have been selected for their simplicity, so you don’t have to spend several weeks designing art, levels, scripted dialogue, or complicated AI. These are clones designed to be doable in roughly a weekend. A Mario or Zelda clone would be complicated to put together, but a Tetris or Asteroids clone would be doable in a weekend.
Orisinal Games:

The Orisinal website has a great collection of Flash games with very simple mechanics that can be copied. http://www.ferryhalim.com/orisinal/
I especially recommend Winter Bells, A Daily Cup of Tea, Bugs, and Hold the Rope!
The Wikipedia entry for video game clones also lists some ideas.
Games from “Invent Your Own Computer Games with Python” and “Making Games with Python & Pygame” books:
These games are described in these free Python programming books and their source code is available. However, you can make your own variants.
1. Dodger

Description: Several bad guys fall from the top of the screen, and the user must avoid them. The player can be controlled with the arrow keys or more directly with the mouse. The longer the player lasts without being hit, the higher the score.
Variations: Have enemies fall at different rates and be different sizes. Have enemies fall from more than one side of the game. Have power up pickups that grant invulnerability for a while, slow down bad guys, give the player a temporary “reverse bad guys” power, etc.
This game is covered in Chapter 20 of “Invent with Python”
Download Source: dodger.zip
2. Memory Puzzle

Description: A board full of overturned cards. There is a pair for each card. The player flips over two cards. If they match, then they stay overturned. Otherwise they flip back. The player needs to overturn all the cards in the fewest moves to win.
Variations: Provide “hints” in the form of four possible matching cards after the player flips the first one. Or, quickly overturn groups of cards at the beginning of the game.
This game is covered in Chapter 1 of “Making Games with Python & Pygame”
Download Python Source: memorypuzzle.py
3. Sliding Puzzle

Description: A 4×4 board of numbered tiles has one missing space and is randomly set up. To win the game, the player must slide tiles over to put the tiles back in order.
Variants: Instead of numbers, you can have a scrambled picture cut up into 4×4 tiles.
This game is covered in Chapter 4 of “Making Games with Python & Pygame”.
Download Python Source: slidepuzzle.py
4. Simon

Description: Four colored buttons light up in a specific pattern. After displaying the pattern, the player must repeat the pattern by clicking the buttons in proper order. The pattern gets longer each time the player completes the pattern. If the player presses a wrong button, the game ends.
Variant: A nine-button version can add challenge to this game (but more than that would probably just be tedious.)
This game is covered in Chapter 5 of “Making Games with Python & Pygame”.
Download Pyhton Source: simulate.py
5. Nibbles

Description: A worm or snake constantly moves around the board. The player controls the direction the “head” of the worm moves, and the worm must try to eat apples that randomly appear. Eating an apply causes the worm to grow in length. The game ends if the worm crashes into the edge of the board or into itself.
Variants: Add walls to the level, instead of just a blank rectangle. Add power ups that the worm can pick up. Add bad guys that move around the board that the worm must avoid. Have two worms that the player must control simultaenously. Tron (see below) is a two-player variant of this game.
This game is covered in Chapter 6 of “Making Games with Python & Pygame”.
Download Python Source: wormy.py
6. Tetris

Description: Shapes made up of four blocks fall from the top of the board. The player must rotate and place them to create full rows with no gaps. When a full row is made, the blocks in that row disappear and the blocks above it move down. The game ends if the board fills up.
Variant: Several Tetris variants are listed on Wikipedia. http://en.wikipedia.org/wiki/List_of_Tetris_variants
This game is covered in Chapter 7 of “Making Games with Python & Pygame”.
Download Python Source: tetromino.py
7. Katamari Damacy

Description: The original Katamari Damacy game was in a 3d world, but a 2d version is also easy to implement. The player controls a small object in a world of different-sized objects. Touching the smaller objects grows the player, touching the larger objects damages or shrinks the player. The player wins when they reach a certain size.
A flash version of 2D Katamari is available.
This game is covered in Chapter 8 of “Making Games with Python & Pygame”
Download Source: squirrel.zip
8. Sokoban

Description: The player is in a level with objects that need to be pushed over goals. The objects can only be pushed, they can’t be pulled. This game does require some effort to design levels for, but Sokoban levels have been designed by others and published on the web.
Variant: Add all sorts of level gimmicks: teleport tiles, conveyor belts, buttons that open doors/bridges, buttons that need an object left on them to keep a door open.
This game is covered in Chapter 9 of “Making Games with Python & Pygame”.
Download Source: starpusher.zip
9. Othello

Description: On a grid, a black and white player places tiles of their color on the board. The opponent’s tiles between the newly placed tile and that player’s existing tiles are flipped to become the color of the player’s tiles. The game ends when the board fills up and the player with the most tiles of their color wins.
Variant: Three player Othello with three different colors. Non-square boards.
This game is covered in Chapter 10 of “Making Games with Python & Pygame”.
Download Source: flippy.zip
10. Flood It

Description: A grid of six colors of tiles starts off randomly. The player can do a “flood fill” on the top left tile, changing the color of any adjacent tiles of thesame color. The player wins if they are able to make the entire board a single color within a certain number of moves.
Variants: Power ups gained when a certain tile is changed.
This game is covered in Chapter 10 of “Making Games with Python & Pygame”.
Download Source: inkspill.zip
11. Connect Four

Description: Two players of different colors drop their tokens on an upright board. The player to make four tokens in a row, column, or diagonal wins. Creating an AI for this requires a simple minimax algorithm.
Variant: Different board sizes. Walls inside the board that appear when the spaces beneath them are filled.
This game is covered in Chapter 10 of “Making Games with Python & Pygame”.
Download Source: fourinarow.zip
12. Bejeweled

Description: The board is filled with seven different types of jewels. The player can swap two adjacent jewels to form a three-in-a-row, causing the jewels to disappear and the jewels on top of them to fall down. Creating chain reactions gives bonus points.
Variant: Different power ups for matching a particular jewel. Be able to sometimes swap jewels that are not adjacent to each other. Timed games.
The original Bejeweled game and its sequels are at http://www.bejeweled.com/
This game is covered in Chapter 10 of “Making Games with Python & Pygame”.
Download Source: gemgem.zip
Board Games:
Board games are a good source for game clone ideas. A game like Monopoly has far too many rules to put together in a short time frame, but here’s a list of board games that have simple mechanics. Chess, Go, and Stratego may be too complicated to create an AI opponent, but in that case you can just make it a two-player game. These games don’t really have variants,
13. Mancala

YouTube video showing gameplay. Mancala rules
Description: A stone capture game where the board is made up of 12 pits and a “score pit” that the player tries to move their stones into. A simple minimax algorithm can be used by the AI.
Variants: Wikipedia has a list of “mancala games”.
Source code for Awale, a Mancala variant.
14. Tic-tac-toe
Wikipedia page explaining rules.
Description: Players put down their X or O symbol on a 3×3 board and try to get three in a row.
Variants: Using a 3x3x3 board for 3D Tic-tac-toe. Wikipedia has a list of variations.
15. Quarto

Quarto rules YouTube video explaining the rules
Description: Two players take turns setting one of the 16 pieces which is either: tall/short, light/dark, square/circular, and hollow/solid. The goal is to get four in a row of a common trait.
Variants: You can increase the board size and the number of types of pieces.
16. Abalone

Wikipedia page with game rules. YouTube video explaining the rules.
Description: Players move their marbles around a hexagonal board, trying to be the first to push six of the opponent’s marbles off the edge of the board.
17. Quoridor

YouTube video explaining the Quoridor rules
Description: Two players try to move their token to the other side of the board. On their turn, they can either move their token one space or place a wall on the board. A player cannot completely seal in the other player with a wall. An AI for this game may be too complex, but a two-player version should be simple to implement.
Variants: See Minotaurus, the next game.
18: Minotaurus
YouTube video showing gameplay.
Description: This game is essentially a more complex and multiplayer version of Quoridor, with a “Minotaur” monster added in that can attack players.
Variants: Add different level/wall designs instead of the standard board. Add teleports, or buttons that can activate doors and bridges.
19: Stratego

YouTube video explaining the rules and demonstrating gameplay. Wikipedia page explaining rules.
Description: Two players set up army units on the board and try to determine the strength of their opponent’s units. Disinformation is an important aspect of the game.
20: Blackjack
Rules of Blackjack
Description: Blackjack is a classic card game that is simple enough to implement a dealer AI for.
Variants: Variants of Blackjack are listed on the Wikipedia page.
21: Scrabble
YouTube video explaining the rules
Description: Player form words from letter tiles on a board. Rare letters are worth more points. Some spaces on the board give letter or word bonuses. You will need a dictionary file for this program, which you can download from http://wordlist.sourceforge.net/.
Variants: There are too many to list here. See the Wikipedia entry for Scrabble Variants.
22: Grid Lock / Traffic Jam

YouTube video showing gameplay.
Description: The player must slide a target car through an exit, but other cars are blocking the way. Cars can only be moved vertically or horizontally depending on their starting orientation. Level designs can be copied from existing games.
23: Yahtzee
Yahtzee rules explained.
Description: Dice rolling game where the players try to achieve specific patterns of rolls.
Variants: Variants are listed on the Wikipedia page.
24: Risk

YouTube video of Dicewars gameplay.
Description: Each territory has a certain number of armies which can be used to attack adjacent territories. The player can attack as often as they want, but conquering too many territories stretches out their troops so that the territories can be reclaimed easily. Additional armies are given based on conquered territories, so not expanding fast enough will also lead to losing. A straight forward AI is relatively easy to produce.
Variants: Dice Wars is a high-speed Flash game that is similar to Risk.
25: Checkers / Draughts
YouTube link of a Checkers game.
Description: A player moves their pieces diagonally on a board and tries to “jump” the opponent’s pieces.
Variants: Some variants are listed on the Wikipedia page for Draughts.
26: Chess
Description: Chess is a classic game, and the rules are explained on Wikipedia.
Variants: Some variants are listed on the Wikipedia page for Chess Variants.
27: Go
Rules explained YouTube video show
Description: Players take turns laying down stones and try to capture areas of the board. See the rules for full details. Even simple Go-playing AIs require deep levels of knowledge, but a two-player game is easy to create.
Action Games:
28: Asteroids
YouTube video showing gameplay
Description: The player rotates a ship to shoot asteroids, which break into two smaller asteroids when hit. The player must avoid being hit by the asteroids which slowly move around the screen. The player has no brakes, and can only slow or stop by using thrust in the opposite direction they are traveling.
Variants: Having different weapons and an occasional UFO that shoots directly at the player.
29: Space Invaders
YouTube video showing gameplay
Description: A few rows of enemies gradually makes they’re way down to the player. The player must shoot them all before they reach the bottom.
30: Tron
YouTube video showing gameplay
Description: Players control a constantly moving object that leaves a trail of walls behind it. The player who avoids crashing into a wall longest wins.
Variants:
31: Missile Command

YouTube video showing gameplay
Description: Missiles are shot up from the ground to hit falling meteors before they hit cities. The missiles must be timed so that they reach their target at the same time that the meteor is there.
Variants: See Rampart below. Different weapon types (the kind used in Scorched Earth) are also possible.
Python source code
32: Pong
YouTube video showing gameplay
Description: A tennis game where players bounce a ball passed the other.
Variants: Several of the same variations found in Arkanoid can be used in Pong. Obstacles can be placed on the map instead of just an open field.
33: Arkanoid

YouTube video showing gameplay
Description: The player controls a paddle that bounces a ball off of bricks in the level. The bricks break when the ball bounces off of them. The level is cleared when all the bricks are destroyed.
Variants: Power ups fall from smashed blocks, including: triple ball, longer paddle, ball breaks through bricks, a laser shoots out from the paddle.
Python source, another Python source, and another, and another.
34: Maze
Wikipedia entry on Maze Generation Algorithms
Description: Player runs through a maze to the exit. This is more of an exercise in writing maze-generation algorithms.
Variants: Teleports, buttons to control doors, keys to unlock doors, having multiple characters to move around that must work in sync to unblock each other’s paths.
Python source code, and another.
35: Scorched Earth / Worms / Gorillas / Angry Birds

YouTube video showing gameplay
Description: Players control tanks on a 2D hilly terrain and enter the numeric angle and velocity of a cannonball shot. The object is hit the other player’s tanks.
Variants: Angry Birds is a version of this game that adds a physics engine instead of hills. Different weapon types besides the standard cannonball can be added. Several UI improvements can be made over the original game (using the mouse to enter the angle and velocity, displaying the previous turn’s angle and velocity, etc.) Destructible terrain and being able to move the tanks adds a new dimension to the game.
36: Lunar Lander

YouTube video showing gameplay
Description: The player controls a ship that must gently land on a flat surface of the moon. The ship has limited fuel, and using the thrusters affects the momentum of the ship (much like Asteroids).
37: Snood / Bust-a-Move

YouTube video showing gameplay of Snood YouTube video showing gameplay of Bust-a-Move
Description: The top of the board is filled with different colored bubbles. The player must shoot bubbles from the bottom to form a set of three bubbles of the same color in a row to make them disappear. The ceiling lowers over time. The player wins if the board is cleared of bubbles, and loses if the bubbles reach the bottom.
Variants: This is a similar game to Bejeweled, and the power ups used in that game could be used in this one.
38: Fruit Ninja
YouTube video showing gameplay
Description: Objects are thrown up over the screen and the player must drag the mouse over them.
Variants: Bonuses for combos. Some objects cause the player to lose if they are touched.
39: Last Stand

Link to the original Flash game
Description: On each round, a wave of zombies attacks a barricade while the player shoots from behind it. Several shots are needed to kill a zombie and accuracy counts. When the zombies reach the barricade they begin to damage it. The player loses if the barricade is destroyed. After each round, the player can spend actions on finding new weapons, finding other survivors to help defend, or repairing the barricade.
Variants: Different zombie types (armored, fast moving-dog zombies, etc.) and weapons can be used (mines, grenades, traps).
40: Duck Hunt
YouTube video showing gameplay
Description: Ducks fly around the screen and the player must click on them to shoot them. The player has limited ammo.
Variants: The flight patterns of the ducks/objects can be changed.
41: Rampart

YouTube video showing gameplay
Description: The player alternates between building fortifications (to house cannons) and shooting at incoming ships. This game is similar to Missile Command, with a building mechanic added in.
Variants: Different enemy types (slow moving, armored ships or fast moving airplanes) and weapons can be added. Add different strength walls to build.
42: Bloxorz

YouTube video showing gameplay
Description: A puzzle game where the player must roll over a 2×1 brick to an exit point on the map. The brick cannot be moved off the edge of the board, and since it can only be flipped end over end and not slid around, the 2×1 nature restricts the types of moves it can make.
43: Dr. Mario
YouTube video showing gameplay
Description: A Tetris-like game where two-colored pills fall on different colored germs. Forming four in a row of the same color germ/pills causes them to disappear. The player wins when all the germs are cleared from the board, and loses if the pills fill up the board.
Variants: Similar to Puyo Puyo.
44: Kirby’s Avalanche / Puyo Puyo
YouTube video showing Kirby’s Avalanche gameplay Wikipedia entry for Puyo Puyo
Description: Essentially like a two-player Dr. Mario without the germs.
45: Fire ‘N’ Ice

YouTube video showing gameplay
Description: A very original but obscure puzzle game on the NES. The player controls a wizard who can make and unmake ice cubes, which need to fall on all the fire in a level to clear it. The ice can also be used as platforms, and individual blocks of ice can be pushed around. (As a platformer, making a clone of this might be a bit more involved. But the concept is original enough where I think it’d be worth the effort.)
46: Typespeed

YouTube video showing gameplay
Description: A typing game where words slowly move to the right side of the screen. The player must type the word to make them disappear. The player loses after enough words hit the right side of the screen.
47: Diner Dash
YouTube video showing gameplay
Description: A game where several different tasks in sequence must be managed simultaneously. Diner Dash has a restaurant theme, but other themes could be applied.
Variants: Usually there are ways to streamline tasks by doing them in a certain order (e.g. the player can carry meals for two tables at the same time).
48: Pipe Dream

YouTube video showing gameplay
Description: The player must put down different shaped pipes on the board. The pipes cannot be rotated or moved after placement, but the player does get to see the next several pipes that will be used. A little after the start of the game, water begins to flow through the pipes.
49: Zoop

YouTube video showing gameplay
Description: Colored bubbles begin to appear from four sides of the board. The player can assume the color of the bubbles, and then destroy bubbles of a similar color. The game ends if the bubbles fill up one side of the board.

May 14, 2012 05:21 AM
May 13, 2012
This is to inform you about the new stable release of Nuitka. Please see the page “What is Nuitka?”for clarification of what it is now and what it wants to be.
This release is a continuation of the trend of previous releases, and added more re-formulations of Python that lower the burden on code generation and optimizations.
It also improves Python3 support substantially. In fact this is the first release to not only run itself under Python3, but for Nuitka to compile itself with Nuitka under Python3, which previously only worked for Python2. For the common language subset, it’s quite fine now.
Bug fixes
- List contractions produced extra entries on the call stack, after they became functions, these are no more existent. That was made possible my making frame stack entries an optional element in the node tree, left out for list contractions.
- Calling a compiled function in an exception handler cleared the exception on return, it no longer does that.
- Reference counter handling with generator “throw” method is now correct.
- A module “builtins” conflicted with the handling of the Python builtins module. Those now use different identifiers.
New Features
New “metaclass” syntax for the “class” statement works, and the old “__metaclass__” attribute is properly ignored.
# Metaclass syntax in Python3, illegal in Python2
class X(metaclass = Y ):
pass# Metaclass syntax in Python2, no effect in Python3
class X:
__metaclass__ = YNote
The way to make a use of a metaclass in a portable way, is to create a based class that has it and then inherit from it. Sad, isn’ it. Surely, the support for “__metaclass__” could still live.
# For Python2/3 compatible source, we create a base class that has the metaclass # used and doesn't require making a choice. CPythonNodeMetaClassBase = NodeCheckMetaClass( "CPythonNodeMetaClassBase", (object, ), {} )The “–dump-xml” option works with Nuitka running under Python3. This was not previously supported.
Python3 now also has compatible parameter errors and compatible exception error messages.
Python3 has changed scope rules for list contractions (assignments don’t affect outside values) and this is now respected as well.
Python3 has gained support for recursive programs and stand alone extension modules, these are now both possible as well.
New Optimizations
Avoid frame stack entries for functions that cannot raise exceptions, i.e. where they would not be used.
This avoids overhead for the very simple functions. And example of this can be seen here:
Optimize “len” builtin for non-constant, but known length values.
An example can be seen here:
# The range isn't constructed at compile time, but we still know its length.
len( range( 10000000 ) )
# The string isn't constructed at compile time, but we still know its length.
len( "*" * 1000 )
# The tuple isn't constructed, instead it's known length is used, and side effects
# are maintained.
len( ( a(), b() ) )
This new optimizations applies to all kinds of container creations and the “range” builtin initially.
Optimize conditions for non-constant, but known truth values.
At this time, known truth values of non-constants means “range” builtin calls with know size and container creations.
An example can be seen here:
if ( a, ):
print "In Branch"
It’s clear, that the tuple will be true, we just need to maintain the side effect, which we do.
Optimize “or” and “and” operators for known truth values.
See above for what has known truth values currently. This will be most useful to predict conditions that need not be evaluated at all due to short circuit nature, and to avoid checking against constant values. Previously this could not be optimized, but now it can:
# The access and call to "something()" cannot possibly happen
0 and something()
# Can be replaced with "something()", as "1" is true. If it had a side effect, it
# would be maintained.
1 and something()
# The access and call to "something()" cannot possibly happen, the value is already
# decided, it's "1".
1 or something()
# Can be replaced with "something()", as "0" is false. If it had a side effect, it
# would be maintained.
0 or something()
Optimize print arguments to become strings.
The arguments to “print” are now converted to strings at compile time.
becomes:
Combine print arguments to single ones.
When multiple strings are printed, these are now combined.
becomes:
Organizational
- Enhanced Python3 support, enabling support for most basic tests.
- Check files with PyLint in deterministic (alphabetical) order.
Cleanups
- Frame stack entries are now part of the node tree instead of part of the template for every function, generator, class or module.
- The try/except/else has been re-formulated to use an indicator variable visible in the node tree, that tells if a handler has been executed or not.
- Side effects are now a dedicated node, used in several optimizations to maintain the effect of an expression with known value.
New Tests
- Expanded and adapted basic tests to work for Python3 as well.
- Added reference count tests for generator functions “throw”, “send”, and “close” methods.
- Cover calling a function with “try/except” in an exception handler twice. No test was previously doing that.
Summary
This release offers enhanced compatibility with Python3, as well as the solution to many structural problems. Calculating lengths of large non-constant values at compile time, is technically a break through, as is avoiding lengthy calculations. The frame guards as nodes is a huge improvement, making that costly operational possible to be optimized away.
There still is more work ahead, before value propagation will be safe enough to enable, but we are seeing the glimpse of it already. Not for long, and looking at numbers will make sense.
May 13, 2012 10:18 PM
Being the language nerd that I am, I actually find it fun to learn new programming languages. Now typically this is nothing more than me reading all of the official documentation and writing some toy examples that give me a very shallow, quick-and-dirty feel for a language. Since I have been involved in language design for nearly a decade (started participating on python-dev in June 2002) and have done toy examples now in 18 languages (17 actually still run; I have never bothered to get Forth to work again after a gforth change broke my code), this is actually usually enough for me to grasp the inspirations for a language and thus understand its essence.
At work I have been doing some JavaScript work for an internal Chrome extension and dashboard and so that led me to want to look into what Dart had to offer over JavaScript. I know the language is only at version 0.09 (and still changing weekly), but the fundamentals are there so I wanted to see what the general feel of the language is (and will continue to be).
I also know Dart is somewhat controversial for some people. Personally, I fall on the "competition is good" side of the argument, not the "OMG fragmentation" side. I want ECMAScript Harmony to still happen and give me a cleaner, tighter, more functional JavaScript, but that doesn't mean Dart doesn't have a place in the world as a cleaner OO language for the web. Besides, me thinking otherwise would make me a massive hypocrite as I began working on Python before it was cool (I feel like I need a hipster meme for that statement, but I digress) and I have worked hard to convert people to Python from other languages. Hell, I have tried to foster competition between the Python VMs to get them to push each other to perform better and be ever more interoperable. IOW I don't totally buy this fragmentation argument.
Going into learning Dart I knew who was involved with the language which is what will inherently define how a language feels. I knew Lars Bak of V8 helped design the language, which meant it would have some design restrictions put on it to make it have a damn fast VM. Josh Bloch has been helping to design Dart's library which meant some JDK feel to it. I also know Jim Hugunin is involved which should also help with the VM speed. So fast with an API designed like the JDK.
What did I find? A language with a damn fast VM and a standard library that felt like the JDK. =) Take OO as a Python programmer would expect (e.g. pure OO where everything is an object, not dogmatic OO like Java where everything has to be in an class definition), make types entirely optional for testing and tooling purposes but enough support to use interfaces and generics, and then toss in abilities based on what JavaScript allows and then you have a good idea of what Dart offers.
So, Dart has optional typing. In case you have not heard, Dart does not use type information at runtime for performance and only throws any form of fit if a type doesn't match what is specified unless you run in checked mode. If you do that then you get warnings about possible type issues. But Dart's type system is unsound so don't expect typing to catch every error that a more strict type system might even when you run in checked mode. Dart views types as helpful documentation and a way to help tools assist with things, period. I actually find it rather refreshing to have a language that treats types as just documentation since that is really what they are for the programmer (VMs can use it for performance, but it isn't required for good performance and type safety only saves you from a minor set of bugs which every Python programmer probably realizes eventually =).
But that's even if you bother with types! You can write all of your code without types and everything will run without issue. Even generics are optional, so you can declare a function accepts a List or List; Dart doesn't care either way and it alleviates covariance/contravariance headaches by not caring if you don't care either. It's actually rather nice to have non-library code be written quickly using dynamic typing and only add in the type information for library code where you care about what interface is expected. IOW I think Dart strike a nice balance with how it does typing and I actually feel fine using types when I know what I expect to accept in my own code that I don't expect anyone else to rely upon.
Dart is OO, not prototypical like JavaScript. It's single-inheritance, which I'm fine with. It does have interfaces as one would expect in a statically typed language, but it softens their expense by allowing one to define a default implementation of an interface. What this means is that the Map interface will also give you a HashMap instance if you call new Map(). I suspect they snagged the idea from Scala where you have the Map class which hides HashMap from the user if you simply don't care about what Map implementation you use.
It does have a modicum of privacy by using a leading underscore for signaling something is private, much like Python. But the privacy is enforced at the library-level or is public, period. Every field automatically has a getter and setter defined for them, so there is no way to force a private field (which I think is a good thing since I find private privacy bloody annoying). I also like that getters and setters are directly supported by the language with automatic generation show you don't ever have to see a setSomething()/getSomething() function call just to read/write a field, but you can do something like Python's properties very easily.
The standard libraries are fine and just feel like the JDK. Things are very much LBYL rather than EAFP. I am willing to bet (although I have not tested this) that exceptions are a little expensive in Dart (since exceptions are hard to optimize) and so they would rather go the LBYL way. But they still went a little overboard in my opinion on some things (e.g. the list interface has a last() method instead of supporting negative indexes). But there is nothing there that is making me run away screaming.
One place I do think Dart could use some improvement is simplifying their constructor rules. Upfront Dart has some nice syntactic sugar for a construction where you directly specify how a constructor's arguments map to instance fields, avoiding having to declare the constructor parameters and then also write an assignment. OK, I like that.
Dart also has initializer lists which let you initialize final fields. OK, that's cool and a nice idea taken from C++.
Constructors are not inherited. OK, that's fine since you probably want to be explicit about how you tweak stuff. But there is an exception about the default, no-argument constructor calling the superclass' no-argument constructor. So while not technically inherited, it might as well be in that single instance. And all defined constructors will automatically call the default constructor, which if it isn't defined you must explicitly call a constructor somehow (probably in the initializer list of your constructor). Um, OK...
And you have named constructors. This gets you around from the lack of type-based method overloading for constructors. OK, I can go with that.
You also have constant constructors since fields can only be initialized to compile-constant values. Fine, that's for performance and determinism in instance creation, so I can grasp the desire for that.
And then you have factory constructors. OK, this is where I go "WTF people". This is so that you can have a constructor that actually doesn't create a new instance but instead can return something else other than a new instance (think of Python's __new__() or any of Java's static factory methods). But this lets you use the new keyword on a factory constructor instead of using a static method. And that to me seems unneeded.
So lets recap what constructor options we have. We have regular constructors, default and defined, which supports initialize lists. You have named constructors. There are constant constructors. And you also have factory constructors. If you don't count the default constructor as special that means Dart has four types of constructors. WTF!?! I realize that Java's FactoryFactoryOfFactories crap has probably spooked the crap out of the Dart designers, all the while having Java influences making them think they need the new keyword for anything that would return an instance of a class, but this seems a bit much. Dart's function definitions are rich enough to allow for optional arguments, etc. which would suggest that the typical constructor can do the job of named constructors with static methods picking up the slack where absolutely necessary where factory constructors are used. Maybe I'm missing something here, but I think they tried to design for everything that is bad about Java's constructor mess without stopping to think what their function definitions already buy them, all while making sure the new keyword was used.
Luckily that is the only bit of Dart that I found poorly designed. Everything else is reasonable and something any JavaScript programmer will be somewhat familiar with or quickly grasp.
Now as I said, I only did toy examples in Dart beyond reading the docs from beginning to end. If I had more time this weekend I may have done one more coding example that was more involved, but I ran out of time. But based on what I have read and what I learned, I am happy with Dart and would be content in using it for programming for the Internet. I would also be totally happy being asked to use it in a situation where others wanted to use types (e.g. I would be fine ditching Java for Dart if people really felt the need to hold on to their types).
May 13, 2012 10:11 PM
As there seems to be some confusion when hard tab characters (ASCII code 9) are appropriate in source code files here is a rule:
1) Never use hard tabs
1. 1) Unless your source code is hard tab sensitive (only such format I know is Makefile)
Reasons not to use hard tabs
- Due to legacy, different text editors treat hard tabs different. UNIX text editors prefer hard tab is 8 spaces, Windows text editors and IDEs (Eclipse) prefer that a hard tab is 4 spaces.
- The hard tab length agreement between different text editors cannot be reached
- The hard tab length agreement between people cannot be reached
- Thus, hard tabs may break source code readability and editability if there is more than a single person editing the file. They will open the file in an editor with different tab settings, edit it and next time you open the file it is ruined and all indentations are wrong.
- This is even worse on white space sensitive languages (Python, CoffeeScript) as this might actually cause syntax errors or programming logic errors
However, you can avoid this problem in the first place if you do indentation using soft tabs (spaces) instead.
Even if you were the single person in the world editing the text file, even you might switch the text editor in some point and accidentally shoot yourself in the leg.
Using soft tabs for indentation and having no hard tabs should not be a problem because
- All text editors can convert tabs to spaces in fly, when editing the file. Please note me if there are commonly used editors, besides Windows Notepad, which doesn’t do it yet.
- Text editors usually have different settings to tab key length and indentation settings. The latter is what you really want to adjust.
Pseudo-arguments for using hard tabs
- It makes the file size smaller: you really care about those twenty bytes on our terabyte hard disks?
- This one I made up: spaces count toward the file size in web stuff, because visitors download the files. However if those bytes really matter you that much you should be using a minimizer in the first place.
- I like them arguments…: rationale not involved
- The change resistance in human nature
You might have a legacy software project having its legacy style guides. If the project big, e.g. Linux kernel, the switching cost may be very high and not affordable. However, even with this kind of codebase, you can gradually replace hard tabs away.
Style guides
Text editors
If you are a text editor author, make sure your text editor ships with hard tabs turned off by default, especially for whitespace sensitive languages if you vary tab policy by file type.
Note that this blog post, and the situation, could have been avoided if
- All text editors would have sticked to soft tabs by default
- All text editors would have sticked to a hard tab is 8 spaces by default
But in some point (when?) someone (who?) decided to make our life little more complex.
Tools for managing hard tab policy in your software project
Subscribe to this blog in a reader
Follow me on Twitter
May 13, 2012 12:16 PM
This is part 3 of a series on MCS:
- MCS background
- fmcs - find the MCS of a set of compounds
- Finding the MCSes for the ChEBI ontology
The industrious folks at EBI have been developing ChEBI, which expands to
"Chemical Entities of Biological Interest." Quoting Wikipedia, "[ChEBI] is a database and ontology of molecular entities focused on 'small' chemical compounds, that is part of the Open Biomedical Ontologies effort."
They define several distinct ontologies. One is a chemical structure
ontology. For example, the identifier CHEBI:33567 contains
catecholamine, and a few examples of catecholamines are hexoprenaline
(CHEBI:37950), arbutamine (CHEBI:50580), L-isoprenaline
(CHEBI:6257). In addition, catecholamine is a catechol (CHEBI:33566),
which in turn is a benzenediol (CHEBI:33570), and so on. A group can
have more than one parent; catecholamine is also a monoamine molecular
messenger (CHEBI:25375).
The end result is a hierarchial structure. The bottom of the hierarchy
are structures, and intermediate nodes are such that all children of
the node have some common property.
Some of these common properties map directly to a common
substructure. For example, CHEBI:33853
contains phenols, so every compound under that node has "one or more
hydroxy groups attached to a benzene or other arene ring."
However, not all of them do. As Chepelev, Hastings, Ennis, Steinbeck,
and Dumontier pointed out in "Self-organizing
ontology of biochemically relevant small molecules", BMC
Bioinformatics 2012, 13:3, the term "'ester' includes compounds that
conform to C(=O)OC (i.e. carboxylic esters) and C(=S)OC patterns, among others."
Other cases can't even be represented as SMARTS. They give "bicyclic"
as one such example.
Can I find the MCS of all structures in a node in the ontology?
I was curious to see if I could use their data set as a test of fmcs. If their
intermediate nodes have a machine-readable way to tell if it's a
purely substructure-based node, and if I could get the size
information, then I could get all the structures underneath it, find
the MCS, and compare my answer to theirs.
Alas, they don't have that annotation information. It's something they
are working on, but I didn't get the impression that it's a high
priority. (I don't see why it should, either.)
Still, it's an interesting thought - what if I were to generate the
MCS for all nodes, and visualize the results somehow?
It took a bit longer than I thought, but I finally downloaded their
ontology (in OBO format), parsed it, extracted the hierarchy, figured
out the compounds in each node, tossed out the structures that RDKit
couldn't parse, and the nodes which didn't have at least two remaining
structures in them.
One that was done, I let my MCS algorithm at it. It took about 50
minutes to process. (Well, I had a 15 second timeout on the MCS. I've
found that 15 seconds is usually good enough.)
I also developed a visualizer for the result, using Karen Schomburg's
SMARTSviewer and
Daylight's depictmatch.cgi
Oooh! More pictures!
Here's a snapshot of one of the successful cases, CHEBI:16648,
which is dialkyl phosphate:

Most of the results aren't as clear-cut. For example, CHEBI:16389
contains the ubiquinones. I found the MCS:

which is nearly right, but the Wikipedia page for Coenzyme_Q10
("Coenzyme Q10, also known as ubiquinone, ...") shows a
methyl attached to the top-most oxygen this SMARTS depiction. This is because
CHEBI:18238
is a structure in the set which does not have that methyl attached!
It this methyl important? I don't know. I'm not a chemist, and this
requires expertise I simply don't have.
An oopsie in the oxolanes?
What I do know is that there's a mistake in the oxolanes, CHEBI:26912.
Wikipedia calls this tetrahydrofuran
and says it's an 5-membered ring with the formula (CH2)4O. I would
write it as the SMILES/SMARTS "O1CCCC1".
However, my search finds only "OCCCC"; it doesn't find the
cycle. There shouldn't be a problem with this one so I investigated
further, wondering if it was a bug. It ended up that acetylblasticidin S
(CHEBI:2413)
is considered an oxolane. A quick look at the structure though
shows that it has no 5-membered ring.
I think that's an annotation error. BTW, I do not envy the job of
annotator. There's a lot of data to review, and people like me end up
pointing out the mistakes, not the huge amount of work to get all the
other parts right.
Even more pictures... most of the ChEBI ontology!
Do you want to see the output of my full analysis? Do you have a lot
of memory on your computer? If so, download fmcs_chebi.html.bz2. It's
only 7.5 MB but it bzip2 uncompresses to 166 MB. Open fmcs_chebi.html
in your browser, and have fun! (Note: I'll probably delete it after a
month or so.)
BTW: the images are computed on-demand using servers from the
University of Hamburg and from Daylight. I didn't want to show
everything at once since that would put a huge demand on those
servers. Instead, you'll need to press the "Toggle images" button in
order to see the SMARTS and the graphical depiction of the matches.
Comments
If you have comments or questions,
leave them here.
May 13, 2012 12:00 PM
- MCS background
- fmcs - find the MCS of a set of compounds
- Finding the MCSes for the ChEBI ontology
My new MCS program is named "fmcs." It uses RDKit for the cheminformatics and is is
available under the BSD 2-clause license. Many thanks to Roche for
funding the project and making it available under a free
license. Their hope and mine is that fmcs will be included someday as
part of RDKit. For now, you can download it from the Bitbucket
site. My hope is that people will fund me to continue developing the
program.
Show me an example
I'll start with a set of 3669 compounds which I know have a benzotriazole
core. I know this because that data set come from doing a substructure
search. If you want to try this yourself, the SD file is part of the
fmcs distribution.
% fmcs sample_files/benzotriazole.sdf --verbose
Loaded 3669 structures from sample_files/benzotriazole.sdf
[#7]:1:[#7]:[#7]:[#6]:2:[#6]:[#6]:[#6]:[#6]:[#6]:1:2 9 atoms 10 bonds (complete search)
Total time 5.89 seconds: load 2.76 fragment 2.66 select 0.42 enumerate 0.06 (MCS found after 3.13)
The core result is the SMARTS pattern on the second line, which
represents the common substructure. The first and third line show text
sent to stderr when the "--verbose" flag is used. In this case, it
took 2.76 seconds to load the 3669 structures, 2.66 seconds to remove
atom-bond-atom patterns which aren't in all of the structures, 0.42
seconds to select the reference structure, and only 0.06 seconds to do
the actual MCS enumeration algorithm. (It's so fast for this case
because the preprocessing stage was enough to identify the MCS.)
Most people can't look at a SMARTS like
"[#7]:1:[#7]:[#7]:[#6]:2:[#6]:[#6]:[#6]:[#6]:[#6]:1:2" and easily
figure out what it means, so I'll use Karen Schomburg's excellent SMARTSviewer to
render it graphically:
as well as RDKit's image renderer to show the match to the first 10
structures of that data file.
Alternate atom and bond comparisons
ignore atom and bond types
By default, the subgraph matches atoms by element and bonds by bond
type. There are other options. The "--compare topology" option lets
any atom match any other atom, and any bond match any other bond.
% fmcs sample_files/ar_clustered_3D_MM_3.sdf
[#6]-[#6]-[#6]-[#6]-[#6]-[#6]-[#6]-[#6]-[#6](-[#6]-[#6]-[#6]-[#6])-[#6] 14 atoms 13 bonds (complete search)
% fmcs sample_files/ar_clustered_3D_MM_3.sdf --compare topology
[*]~1~[*]~[*]~[*]~[*]~2~[*]~[*]~[*]~3~[*](~[*]~1~2)~[*]~[*]~[*]~1~[*]~[*]~[*]~[*]~1~3 17 atoms 20 bonds (complete search)
[c-2ec28d18-74736162:~/cvses/fmcs] dalke%
Here is a graphical comparison of those two patterns:


That's very interesting. It looks like there's a common substructure,
based on the topology, but not when using on the default match
parameters. Why is this?
It's a matter of bond perception. Some of the rings found by the
topology search are aromatic in some structures but not in others, and
some of the bonds are double in one and single in others. I know I
gave PubChem a SMARTS pattern to find those structures. I wonder how
it ended up like it did.
Match atom types but ignore bond types
The "--compare topology" flag is a shortcut for "--atom-compare any
--bond-compare any". You can chose different options for comparing
atom types and bond type. For example, if you want to compare atoms by
element and ignore bond types then you can do "--atom-compare elements
--bond-compare any".
Coming up with a good example of when to use it is left to the student
as an exercise. (Let me know the answer when you figure it out, so I
can include it here.)
Bond modifiers
Chemists like rings. That's because rings are important. A problem
with MCS is that sometimes it matches a long chain of atoms with a
strange routing through a ring system. Chemists don't always like
that.
If you're one of those people, use the "--ring-matches-ring-only"
flag. This make ring atoms match only ring atoms and chain atoms only
match chain atoms.
Even that might be too generous. Sometimes chemists really want to see
a complete ring in the MCS, and not just a partial one. That is, if
the MCS includes a bond which maps to a ring bond in the original
structures, then the MCS bond must also be in a ring.
If that's what you want, use the "--complete-rings-only" option.
When I figure out good uses cases for these, I'll update the primary
documentation. (I'm told that they are important, but I don't have a
good example for you to understand why.)
All that, and more!
I'm still working on the documentation for the newest features, added
during the last couple of weeks. You can hijack the "isotopes" atom
matcher to define your own atom classes, and specify those classes
through a tag in the SD file. Instead of showing the SMARTS as the
result, you can see the fragment as SMILES, or you can save the
results to an SD file.
Comments
Do you have any comments or questions?
May 13, 2012 12:00 PM
We just released LFS 0.7.3. This is a yet another bugfix release of the 0.7 branch.
Changes
- Bugfix: update product view after images has beend changed; issue #200.
- Bugfix: fixed wrong label for e-mail field; issue #202.
- Bugfix: fixed pagination link. (Maciej Wi?niowski)
- Bugfix: fixed Product.get_product_tax method: added request to parameters; issue #199.
- Bugfix: fixed display of standard price within category products view.
- Bugfix: don't allow pages with same slug.
- Added: added CategoryProductPricesNetNode to lfs_tags.
- Added: added CategoryProductPricesNode to lfs_tags.
- Updated: cleaned up PriceCalculators.
Information
You can find more information and help on following locations:
LFS moved to github
See here for more.
LFS on EuroPython 2012
We are sprinting on this year's EuroPython in Florence. Don't hesitate to join us, see https://ep2012.europython.eu/p3/sprints/ and LFS sprint topics for more.
May 13, 2012 11:46 AM
We just released LFS 0.6.16. This is a yet another bugfix release of the 0.6 branch.
Changes
- Bugfix: fixed pagination within products tab of category management (Maciej Wi?niowski)
- Bugfix: fixed wrong label for e-mail field; issue #202.
- Bugfix: fixed update product view after images has beend changed; issue #200.
Information
You can find more information and help on following locations:
LFS moved to github
See here for more.
LFS on EuroPython 2012
We are sprinting on this year's EuroPython in Florence. Don't hesitate to join us, see https://ep2012.europython.eu/p3/sprints/ and LFS sprint topics for more.
May 13, 2012 11:46 AM