Développement

Entries feed - Comments feed

Thursday, 26 February 2015

Spectateur, custom reports for crash-stats

The users of Socorro at Mozilla, the Stability team, have very specific needs that vary over time. They need specific reports for the data we have, new aggregations or views with some special set of parameters. What we developers of Socorro used to do was to build those reports for them. It's a long process that usually requires adding something to our database's schema, adding a middleware endpoint and creating a new page in our webapp. All those steps take a long time, and sometimes we understand the needs incorrectly, so it takes even longer. Not the best way to invest our time.

Nowadays, we have Super Search, a flexible interface to our data, that allows users to do a lot of those specific things they need. As it is highly configurable, it's easy to keep the pace of new additions to the crash reports and to evolve the capabilities of this tool. Couple that with our public API and we can say that our users have pretty good tools to solve most of their problems. If Super Search's UI is not good enough, they can write a script that they run locally, hitting our API, and they can do pretty much anything we can do.

But that still has problems. Local scripts are not ideal: it's inconvenient to share them or to expose their results, it's hard to work on them collaboratively, it requires working on some rendering and querying the API where one could just focus on processing the data, and it doesn't integrate with our Web site. I think we can do better. And to demonstrate that, I built a prototype. Introducing...

Spectateur

spectateur.jpg Spectateur is a service that takes care of querying the API and rendering the data for you. All you need to do is work on the data, make it what you want it to be, and share your custom report with the rest of the world. It uses a language commonly known, JavaScript, so that most people (at least at Mozilla) can understand and hack what you have done. It lets you easily save your report and gives you a URL to bookmark and to share. And that's about it, because it's just a prototype, but it's still pretty cool, isn't it?

To explain it a little more: Spectateur contains three parts. The Model lets you choose what data you want. It uses Super Search and gives you about the same capabilities that Socorro's UI has. Once you have set your filters and chosen the aggregations you need, we move to the Controller. That's a simple JavaScript editor (using Ace) and you can type almost anything in there. Just keep the function transform, the callback and the last lines that set the interface, otherwise it won't work at all. There are also some limitations for security: the code is executed in a Web Worker in an iframe, so you have no access to the main page's scope. Network requests are blocked, among other things. I'm using a wonderful library called jailed, if you want to know more, please read its documentation.

Once you are done writing your controller, and you have exposed your data, you can click the Run button to create the View. It will fetch the data, run your processor on that data and then render the results following the rules you have exposed. The data can currently be displayed as a table (using jsGrid) or as a chart (using Chart.js). For details, please read the documentation of Spectateur (there's a link at the top). When you are satisfied with your custom report, click the button Save. That will save the Model and the Controller and give you a URL (by updating the URL bar). Come back to that URL to reload your report. Note that if you make a change to your report and click Save again, a new URL will be generated, the previous report won't be overwritten.

As an example, here is a report that shows, for our B2G product, a graph of the top versions, a chart of the top signatures and a list of crash reports, all of that based on data from the last 7 days: https://spectateur.mozilla.io/#58a036ec-c5bf-469a-9b23-d0431b67f436

I hope this tool will be useful to our users. As usual, if you have comments, feedback, criticisms, if you feel this is a waste of time and we should not invest any more time in it, or on the contrary you think this is what you needed this whole time, please please please let us know!

Tuesday, 2 December 2014

Socorro: the Super Search Fields guide

Socorro has a master list of fields, called the Super Search Fields, that controls several parts of the application: Super Search and its derivatives (Signature report, Your crash reports... ), available columns in report/list/, and exposed fields in the public API. Fields contained in that list are known to the application, and have a set of attributes that define the behavior of the app regarding each of those fields. An explanation of those attributes can be found in our documentation.

In this guide, I will show you how to use the administration tool we built to manage that list.

You need to be a superuser to be able to use this administration tool.

Understanding the effects of this list

It is important to fully understand the effects of adding, removing or editing a field in this Super Search Fields tool.

A field needs to have a unique Name, and a unique combination of Namespace and Name in database. Those are the only mandatory values for a field. Thus, if a field does not define any other attribute and keeps their default values, it won't have any impact in the application -- it will merely be "known", that's all.

Now, here are the important attributes and their effects:

  • Is exposed - if this value is checked, the field will be accessible in Super Search as a filter.
  • Is returned - if this value is checked, the field will be accessible in Super Search as a facet / aggregation. It will also be available as a column in Super Search and report/list/, and it will be returned in the public API.
  • Permissions needed - permissions listed in this attribute will be required for a user to be able to use or see this field.
  • Storage mapping - this value will be used when creating the mapping to use in Elasticsearch. It changes the way the field is stored. You can use this value to define some special rules for a field, for example if it needs a specific analyzer. This is a sensitive attribute, if you don't know what to do with it, leave it empty and Elasticsearch will guess what the best mapping is for that field.

It is, as always, a rule of thumb to apply changes to the dev/staging environments before doing so in production. And to my Mozilla colleagues: this is mandatory! Please always apply any change to stage first, verify it works as you want (using Super Search for example), then apply it to production and verify there.

Getting there

To get to the Super Search Fields admin tool, you first need to be logged in as a superuser. Once that's done, you will see a link to the administration in the bottom-right corner of the page.

Fig 1 - Admin link

Clicking that link will get you to the admin home page, where you will find a link to the Super Search Fields page.

Fig 2 - Admin home page

The Super Search Fields page lists all the currently known fields with their attributes.

Fig 3 - Super Search Fields page

Adding a new field

On the Super Search Fields page, click the Create a new field link in the top-right corner. That leads you to a form.

Fig 4 - New field button

Fill all the inputs with the values you need. Note that Name is a unique identifier to this field, but also the name that will be displayed in Super Search. It doesn't have to be the same as Name in database. The current convention is to use the database name but in lower case and with underscores. So for example if your field is named DOMIPCEnabled in the database, we would make the Name something like dom_ipc_enabled.

Use the documentation about our attributes to understand how to fill that form.

Fig 5 - Example data for the new field form

Clicking the Create button might take some time, especially if you filled the Storage mapping attribute. If you did, in the back-end the application will perform a few things to very that this change does not break Elasticsearch indexing. If you get redirected to the Super Search Fields page, that means the operation was successful. Otherwise, an error will be displayed and you will need to press the Back button of your browser and fix the form data.

Note that cache is refreshed whenever you make a change to the list, so you can verify your changes right away by looking at the list.

Editing a field

Find the field you want to edit in the Super Search Fields list, and click the edit icon to the right of that field's row. That will lead you to a form much like the New field one, but prefilled with the current attributes' values of that field. Make the appropriate changes you need, and press the Update button. What applies to the New field form does apply here as well (mapping checks, cache refreshing, etc. ).

Fig 6 - The edit icon

Deleting a field

Find the field you want to edit in the Super Search Fields list, and click the delete icon to the right of that field's row. You will be prompted to confirm your intention. If you are sure about what you're doing, then confirm and you will be done.

Fig 7 - The delete icon

The missing fields tool

We have a tool that looks at all the fields known by Elasticsearch (meaning that Elasticsearch has received at least one document containing that field) and all the fields known in the Super Search Fields, and shows a diff of those. It is a good way to see if you did not forget some key fields that you could use in the app.

To access that list, click the See the list of missing fields link just above the Super Search Fields list.

Fig 8 - The missing fields link

The list of missing fields provides a direct link to create the field for each row. It will take you to the New field form with some prefilled values.

Fig 9 - Missing fields page

Conclusion

I think I have covered it all. If not, let me know and I'll adjust this guide. Same goes if you think some things are unclear or poorly explained.

If you find bugs in this Super Search Fields tool, please use Bugzilla to report them. And remember, Socorro is free / "libre" software, so you can also go ahead and fix the bugs yourself! :-)

Tuesday, 1 July 2014

About Socorro

I have been working on Socorro for about 3 years now. It was about time that I started talking about it on this blog! With this first post, I am inaugurating 2 new tags, socorro and mozilla. I'm also going to add a language tag to my posts, so each new post will either be en or fr. This way, you can choose more accurately what kind of content you want to read from this blog. The previous links on the tags lead to the filtered Atom feeds, and I will add the mozilla feed to the Planet.

So, what is Socorro?

  1. a planet in the Star Wars universe
  2. a city in Brazil
  3. an island in Mexico
  4. a server to process breakpad crash reports

All of those are true, but as you guessed (I hope! ) we will only consider the last option. So basically, Socorro is a software that collects, processes and stores crash reports generated by breakpad. We use breakpad in our desktop software such as Firefox, Firefox for Android, Thunderbird and FirefoxOS. We then have a Web interface that shows information about the stability our those software, and we call it crash-stats. As usual with Mozilla, most of the information on this site is public, the only exceptions being sensitive data like email addresses, URLs, etc.

Most of Socorro's code base in written in Python. The back-end is raw Python based on a tool called configman, developed by my colleagues Lars and Peter, that handles the configuration and is used as a dependency injection system. It allows Socorro to be very modular, and to add or remove components easily without changing any code. We use 3 different databases:

  1. HBase is the primary storage and is there for data consistency (it contains all the data we receive and process and must never lose data)
  2. PostgreSQL is used as the main source of data for the UI (it contains all the processed data and has a lot of materialized views with various computed information)
  3. elasticsearch is used as the secondary source of data for the UI, mainly for everything related to search. This is what I have been mainly working on.

The Web app is based on Playdoh, Mozilla's customized django framework. We have more and more javascript, mostly using jQuery, but it's a bit chaotic at the moment.

Interested in contributing?

If Socorro sounds like a good project to you and you would like to participate, we would be very happy to hear about you! There are a few places where you can start:

You can also join us in Mozilla's IRC server, channel #breakpad. There are a good variety of bugs to fix on Socorro, from pure front-end work to complex back-end Python problems. And if Socorro is not your thing but you still want to help Mozilla fulfill its mission, you can take a look at whatcanidoformozilla.org!

Tuesday, 27 May 2014

Play Michel in Hell, our Ludum Dare 29 game!

Last year, my friend Aurélien invited me to participate with him and a few other friends in the Ludum Dare, for the 26th edition. We made a Flash game, which is probably why I didn't write about it (how could I face my Mozilla colleagues after making a Flash game? ). It's called Sniff and it's about a drug dealer that needs to deliver its magical powder to his customers. As those customers are in a night club, you will need to use the music to find your way through the town. Beware of the cops that want to catch you, and beware of not using the different powers the drug gives you...

Play Sniff

This blog post is not about Sniff, though. After having only organized, and not participated, in our last Game Dev Party Jam, I felt a bit frustrated and really wanted to work on a game. So I called a few friends and invited them to join me for the Ludum Dare 29 weekend. 4 of them answered, and we had a team! Caroline joined us as our graphics person, Pierre-Etienne would take care of all music things, while Maxime and Rémi would join me on the programming of the game.

michell.jpg

The tale of Michell

The theme of this edition of the Ludum Dare was "Beneath the surface". I was not much inspired by it, but I dislike multi-words themes in general. After about 3 hours of brain-storming, we decided to go for a tower defense game, with a bit of Hack 'n Slash in it. The idea was for the player to defend against troops sent from hell: Michell, the hero, peed on Lucifer's flowers, and that didn't make him happy at all. So Lucifer decided to send all his troops to kill him! But Michell is no mere hero, he is a magician that can grow strong plants to help him.

So, there you are on a small platform. Demons will be appearing around that platform in waves, and they will attack you. You can either fight them directly by clicking on them if you can reach them, but that is dangerous. Your other solution is to use your magic to grow powerful plants to help you. Click on a button at the bottom or use the shortcuts, then place your tower. The only limit is that you need to go close to where you want to build the tower, and wait until it is fully grown before you can do something else. The first tower is a bit weak and attacks enemies. The second one is more resilient, but it only slows them down.

Play Michell in Hell

This is the current version of the game. We continued developing the game after the end of the Ludum Dare, and have fixed some pretty big bugs. We also added more content (the second tower, the boss, sounds... ). If you want to see what the game looked like at the end of the weekend, you can play the Ludum Dare version.

The Ludum Dare 29 is now over, and we have the results of the voting. People liked our game, it seems, as we got only above-average marks. Unsurprisingly, the graphics and audio were what people liked the most! Overall we had slightly worst marks than for Sniff, but that doesn't surprise me: the game was less polished at the end of the weekend, with some annoying bugs. I hope people had played the updated version instead, but I realized only too late that I could edit the entry. Anyway, here are our ratings for the Jam competition!

ld29-ratings.png

Notes about Phaser

We used the Phaser game engine for this jam. I had played a little with it before, and I thought it was pretty cool and complete / stable enough. As usual, this assumption was stressed a lot during the weekend! Overall I am satisfied with it, the performance of the game is pretty good, the engine was quite easy to use, and the code of the engine itself is pretty clean. However, here are a few things that I didn't like or feel could be improved.

Documentation. That's the key for every developer facing code. If it isn't correctly documented, it's going to be very hard to use, people will get frustrated and the software will slowly die, or never get used at all. In the case of Phaser, discovery of features was the most difficult thing. I realized several times during the weekend that some things I had coded were already built inside the engine. That is frustrating, especially when coding in limited time like in a Jam. The API documentation was very complete and pretty good in my opinion, but it could do with some work on the search features.

Some things are still buggy, or at least did not behave like we expected them to. For example, we struggled a lot with the physics, and especially with the collision system. Sometimes collisions just stop working if you make objects unmovable. Objects push each others by default when colliding. And there are few incoherences in the collision functions that I would like to fix whenever I can find the time to open a pull request to Phaser...

The groups feature was the most misleading thing we used during the weekend. What we didn't know at first was that groups define the order in which objects are displayed. That's cool, but. If your Game object contains groups, those groups will be displayed in the order they are in Game. That's probably expected and a good behavior, but as we used groups for logical grouping (enemies together, towers together... ) and not for display grouping, we ended up with a messed up displaying. Basically, towers could never be behind enemies, even when that enemy was clearly in front of that tower. Same for the player. So I had to re-work our logic to not use Groups but lists, and use Groups as display layers. A bit confusing.

Overall, I was satisfied with Phaser and I want to use it again on my next Jams. Hopefully I will take some time to fix the few bugs we found during the development of Michell in Hell!

I want to finish this article with a big thank you to Caroline, Maxime, Pierre-Etienne and Rémi who made this game with me. I really enjoyed this weekend with you, and hopefully you did too!

Monday, 8 April 2013

Soviet VS Asteroids

Dear readers,

I am happy to announce today the release of a new game I worked on: Soviet VS Asteroids. The game was developed during the last jam of the Game Dev Party (see the introduction of that 4th jam [fr] or a report of the 2nd edition [en]). The concept is simple: during an entire weekend, 50 people gather, make teams and work on a game, with the goal of having something to show (and to play) in the end.


Greetings, comrade cosmonaut!

This time I decided to work with my friend Aurélien Defossez, who proposed a "planet defense" gameplay. The idea is that you are in space, and asteroids are flying at you. You will need to use your weapons to destroy those nasty asteroids and survive as long as possible. Aurélien gathered a team of 6: he was managing the project and programming, along with Louis-Rémi Babé, Maxime Viry and myself. Mathieu Perez created all the sounds and musics of the game, and did a bit of code as well. Frédéric Ostéréro drew all the beautiful graphics. With this fine team and a lot of work, we demonstrated something pretty good on Sunday evening. But it was not ready for release yet. Over the last 2 weeks, we did some bug fixing, added the missing menus (things like credits or tutorial that do not matter for the demo but are needed when you release the game to the public), and polished the gameplay, mainly by adjusting the difficulty so as many people as possible can enjoy it.

And now, it is time: we believe the game is ready to be played! At this point I hope you are excited and want to download the game as soon as possible. You can do just that by clicking one of those links:

You can play the game with your mouse and keyboard, or with a pad. Make sure your pad is plugged in before you start the game or it will not be detected. You have 2 weapons at your disposal: a rocket launcher and a laser command. You aim at asteroids with the joysticks or your mouse and the Q, A or D keys of your keyboard. If you play with a keyboard, the lasers will fire automatically, and you can shoot rockets by clicking your mouse or hitting the space key. With a pad, you shoot with LS and RS. By pressing the Tab or Enter keys, or the Y button on a pad, you enter the upgrade menu: use your money to make your weapons better, or clear the space around you if you are overrun, or place new lasers or drones around you to improve your defense.

We all hope you are going to enjoy our game! Do not hesitate to make any comments here or to share your high scores! We would love to hear from you.

If you are interested by the technical details, there you go: the game in programmed in lua, using the LÖVE framework (also known as love2d). You can find the source code on github: feel free to fork and open pull requests or issues if you find bugs. Quick feedback on lua: it's nice, but some choices in the design of the language are weird. I definitely prefer Python, but wouldn't mind working with lua again. LÖVE on the other hand was quite a pain to work with, for 2 majors reasons: missing features (no sprite system in a 2d game framework? ) and documentation. As usual, the documentation of a tool is critical and even if the API was well documented, there was almost no tutorial, and no examples of basic features or code.

Play & Enjoy!

Wednesday, 31 October 2012

Web Game Workshop: Creating a Game with Crafty.js

Earlier this month, I gave a workshop in Lyon to teach people how to create Web games with the now famous Crafty.js framework. 13 people attended (out of 15 open places), which appeared to be a good number: I could really help everyone and answer all the questions I received. It was a really good experience, but a short one sadly: we only had 2 hours (30 minutes being me talking about Crafty), and it's really short to be able to actually create a playable game. I think with an hour or two more some people could have had something playable.

Anyway, I created a bunch of content for that workshop, and I wanted to share it. So here it is!

Presenting Crafty.js

I spent the first 30 minutes of that workshop talking about Crafty.js, what it is, what it can do, and how it works. As usual, slides without the actual talk are not really good, but at least you will find some code examples and links to various resources in there. And who knows, maybe someone could make good use of these slides someday?

Creating Web Games with Crafty.js

Workshop: Coding a Web Game

My plan for the coding part was to come with 3 game ideas that people could work on, to provide some help (basic algorithms, some graphic resources) and to give them a working version in the end. That's what I did: I created a simple Snake game, a kind of Fruit Ninja and a Side Runner. After my presentation, I showed the 3 games I coded and asked people to pick one and start working on it. Most people picked the simplest one (some assuming it was the snake, when it was actually the Fruit Ninja clone in my opinion), and no one picked the Side Runner which was certainly harder and mostly impossible to do in less than 2 hours.

After an hour and a half of intense coding, documentation reading and some debugging (I had a few mistakes in my slides sadly), we had some snakes moving and some fruits falling!

I made a simple page with all the resources needed for this workshop:

The Crafty Workshop Awesome Page

There you can find:

  • links to the base template in github or as a zip file
  • short help with algorithms
  • graphics
  • and my own implementation of each game

I really enjoyed doing this, and I wish I can do it again someday! Thanks to everyone who attended and thanks to the Game Dev Party association for organizing this event.

Make Games, Not War /-)

Sunday, 18 December 2011

Component Entity Manager for JavaScript games

Hi everyone!

I recently wrote a library to handle a Component Entity model in a JavaScript game. I need it for my ongoing Fightly Game Engine, which I'm trying to work on. If you don't know what the Component Entity model is, here are great resources about it:

Basically, the idea is to replace classical inheritance with composition. Your game is composed of entities, each being just a list of components. JavaScript's flexibility is well adapted to this sort of programming, as it is easy to change an object to add attributes or methods to it.

That system I implemented is highly based on what Louis Stowasser did on Crafty.js. It works on both server- and client-side, and comes with a few unit tests and examples. Let's first show you how it can be used:

How to use the ComponentEntityManager

Ok, so I like showing code instead of writing English. Here is the most basic way to use that library. First, import and instantiate the Manager:

var cem = require('component-entity-manager'),
    myCEM = new cem.ComponentEntityManager();

Then, declare a new component:

myCEM.c('HelloWorld', function() {
    this.hello = function() { console.log('Hello, World!'); };
});

Now create an entity using this component:

var hi = myCEM.e('HelloWorld');

And finally use that entity the way you like. For example:

hi.hello(); // prints "Hello, World!" in the console

Pretty simple, right? Right, we only printed a "Hello World" but still, we did so by using the Component Entity model! Now you can obviously add a thousand more components, and create hundreds of thousands entities. Let's see a more concrete example before I explain why it is useful.

A more concrete example

See example1.js on github

var cem = require('../../component-entity-manager'),
    // Instanciate the Game Engine
    myGE = new cem.ComponentEntityManager();

// Create a few components that can be used in-game
var Hero = {
    "life": 100,
    "defense": 100,
    "attack": 100,

    "hit": function(opponent) {
        var points = this.attack * 1.1 - opponent.defense;

        if (points > 0) {
            opponent.life -= Math.round(points);
        }
        return this;
    },

    "specialHit": function(opponent) {
        return this.hit(opponent);
    }
}

var Wizard = {
    // this component requires the Hero component, and
    // any entity having a Wizard component will automatically have a Hero one
    "_requires": "Hero",

    "life": 80,
    "mana": 100,

    // "Overwrite" the specialHit method of the Hero component
    "specialHit": function(opponent) {
        var points = this.attack * 1.2 - opponent.defense;

        if (this.mana > 20) {
            points += 20;
            this.mana -= 20;
        }

        if (points > 0) {
            opponent.life -= Math.round(points);
        }
        return this;
    }
}

var Necromancer = {
    "_requires": "Wizard",
    "life": 70,
    "attack": 110
}

var Paladin = {
    "_requires": "Hero",
    "defense": 150
}

// Add those components to the Game Engine so we can use them
myGE.addComponent("Hero", Hero)
    .addComponent("Wizard", Wizard)
    .addComponent("Necromancer", Necromancer)
    .addComponent("Paladin", Paladin);

// Create two entities than we can manipulate
var gerard = myGE.e("Paladin"),
    igor = myGE.e("Necromancer");

// And now play with those entities
console.log("Before we do anything: ");
console.log("  Gerard's life is " + gerard.life);
console.log("  Igor's life is " + igor.life);

gerard.hit(igor);

console.log("\nAfter Gerard hits Igor: ");
console.log("  Gerard's life is " + gerard.life);
console.log("  Igor's life is " + igor.life);

igor.specialHit(gerard);

console.log("\nAfter Igor hits Gerard: ");
console.log("  Gerard's life is " + gerard.life);
console.log("  Igor's life is " + igor.life);

How is this useful?

And how is it better than classical inheritance? Some people answered this better than I could do in other places (see the two links above), but here is the main point. When you come to have a very complex hierarchy, with lots of classes and dependencies between them, you will certainly end up having unneeded code in some of your objects. Let's say you have a few classes: Moving, Vehicle, Car. Vehicle inherits from Moving, Car inherits from Vehicle. Now at some point you want to add a BrokenCar class, to represent a car than cannot move. It seems quite logical to make it inherit from Car as it shares almost everything with it. But that is the point: almost. As you don't want that BrokenCar to move, you will have to overwrite the code from Moving, or to break your entire hierarchy. With composition, you just specify directly what you need in your object. For example, I want this object to be a Car, a Vehicle and a Moving. Or I want that other object to be a BrokenCar, a Car and a Vehicle (but not a Moving). It is more flexible and allows for a wider range of mixing.

Now about that library precisely. The main features are here: you can create components and declare them, express requirements in a component, create entities from one or several components, get entities from their components. It is intended to be used as a building block for any JavaScript game, or any JavaScript game engine. Oh and I'm pretty sure you guys can find some other use cases as well... :)

Licensing

I release this code under a simple MIT license. It's the simplest I know. I'm considering adding a GPL-ish license as well, and maybe some BSD if people ask me to. 

And the future...

There are a few things I want to add to this library: a function to get an entity from it's ID, more unit tests, more options for selectors... But what I would really, really love to hear is everything you have to say! I will gladly accept code reviews, forks, pull requests, emails, comments here... 

Hack & Enjoy! /-)

Tuesday, 15 November 2011

Examples of how to break long lines in Python

I recently started learning Python, and as I am a bad student, I didn't follow the coding style PEP8 recommends. So I'm currently in the process of rewriting all of my code to follow PEP8, and that basically means breaking long lines. I ran into several cases where I didn't know how to break my line, and the Internet doesn't seem to be very helpful about this. But fortunately my awesome coworkers are, so here are some examples of cases I had to deal with, and how I ended up dealing with them.

Before I start showing examples, I just wanted to outline the few rules that matter here about PEP8:

  • Lines must not be longer than 79 characters ;
  • Use 4-space indentation for blocks ;
  • Alignment matters ;
  • The rest of the rules is well described in the PEP8 documentation.

Breaking an if statement

if condition1 and condition2 and condition3 and condition4 and condition5 or condition6:
    do_stuff()

At first I did something like this:

if condition1 and condition2 and condition3 and condition4 and condition5 or \
   condition6:
    do_stuff()

It seemed better to me mainly because that way the second line of conditions is not on the same indentation level than the content of the block, but my coworkers convinced me that using parentheses instead of backslashes is better. Reasons are backslashes are not "pythonic", and the use of parentheses shows the limits of the conditions.

Here is what I then thought would be the best solution:

if (condition1 and condition2 and condition3 and condition4 and condition5 or
    condition6):
    do_stuff()

But it's still not perfect as the block is aligned with conditions, and it makes it difficult to differenciate them. I believe now the best way to go is the following:

if (condition1 and 
    condition2 and 
    condition3 and 
    condition4 and 
    condition5 or
    condition6
):
    do_stuff()

Assert

assert condition, "This is a very long error message because I like to be verbose when I describe assertion errors with this content: %s" % variable

Becomes

assert condition, ("This is a very long error message because I like to be "
                   "verbose when I describe assertion errors with this "
                   "content: %s" % variable)

Or when the condition is long:

assert condition1 and condition2 and condition3 or condition4, (
    "This is a small error message. ")

Other examples?

If you ran into similar examples and couldn't find a documented solution on the Web, please share them in the comments and I'll add them here!

- page 1 of 4