Category Archives: Python

Converting a Python project to PEP8 with Shell

Category : Linux Python

When I started Python I didn’t learn PEP8 immediately so my code was not following the standard format. As I know Bash quite well, I’ve converted my projects later, with the following commands.

Convert tabs to 4 spaces

find . -name '*.py'|xargs pep8|grep W191|cut -d : -f1|xargs sed -i "s/\t/    /g"

Suppress spaces when they’re alone on the line

find . -name '*.py'|xargs pep8|grep W293|cut -d : -f1|sort -u|xargs sed -i "s/^ *$//"

Suppress spaces at end of line

find . -name '*.py'|xargs pep8|grep W291|cut -d : -f1|sort -u|xargs sed -i "s/ *$//"

Add spaces after “:”, “,”

find . -name '*.py'|xargs pep8|grep E231|cut -d : -f1|sort -u|xargs sed -i 's/:\([^ ]\)/: \1/g'
find . -name '*.py'|xargs pep8|grep E231|cut -d : -f1|sort -u|xargs sed -i 's/,\([^ ]\)/, \1/g'

Suppress spaces before or after {} [] ()

find . -name '*.py'|xargs pep8|grep E201|cut -d : -f1|sort -u|xargs sed -i 's/{ */{/g'
find . -name '*.py'|xargs pep8|grep E201|cut -d : -f1|sort -u|xargs sed -i 's/\[ */[/g'
find . -name '*.py'|xargs pep8|grep E201|cut -d : -f1|sort -u|xargs sed -i 's/( */(/g'
find . -name '*.py'|xargs pep8|grep E202|cut -d : -f1|sort -u|xargs sed -i 's/ *}/}/g'
find . -name '*.py'|xargs pep8|grep E202|cut -d : -f1|sort -u|xargs sed -i 's/ *]/]/g'
find . -name '*.py'|xargs pep8|grep E202|cut -d : -f1|sort -u|xargs sed -i 's/ *)/)/g'

Suppress spaces before “(“, “:”

find . -name '*.py'|xargs pep8|grep E211|cut -d : -f1|sort -u|xargs sed -i 's/ *(/(/g'
find . -name '*.py'|xargs pep8|grep E203|cut -d : -f1|sort -u|xargs sed -i 's/ *:/:/g'

Add a blank line at end of file

find . -name '*.py'|xargs pep8|grep W292|cut -d: -f1|while read f; do echo >> $f; done

Add a blank line before “def” or “class”, to be run two times

find . -name '*.py'|xargs pep8|grep E302|cut -d : -f1|sort -u|xargs sed -i 's/^def/\ndef/'
find . -name '*.py'|xargs pep8|grep E302|cut -d : -f1|sort -u|xargs sed -i 's/^class/\nclass/'

Sometimes I don’t really want to cut long lines, so I keep lines up to 120 characters

find . -name '*.py'|xargs pep8 --max-line-length=120

I think that 80 is to restrictive and based on terminals of the last century or on paper sizes that no one uses any more.

However, I’ve learned how to cut long lines with chained calls.

Before:

compte.dernier_solde = SoldeJour.objects.filter(compte_id=compte.id).order_by('-date_solde')[0].solde

After, with parenthesis to tell the Python parser that a single expression is on multiple lines:

compte.dernier_solde = (
SoldeJour
.objects
.filter(compte_id=compte.id)
.order_by('-date_solde')[0]
.solde
)

I’ve also configured Scite, my favorite editor, for spaces and tabs.

use.tabs=0
tabsize=4
indent.size=4

A new Django widget

Category : Python

I’m building websites with Bootstrap and Django. I’ve already created a form on one of them with a file input. The standard file input can’t really be styled with CSS apparently, so I’ve searched for a way to have a nice Bootstrap file input and found this. In short, it uses a button and a text input for display, and a transparent file input above them to use the browser access to local files. Some Javascript makes those two parts communicate.

First I’ve used this manually in a form directly in the template. Today I discovered that you can write your own Django widgets, so I tried to reorganize this file input.

Creating the widget

First I created a widgets directory in my app, with the following files : __init__.py (empty) and styledfileinput.py.

styledfileinput.py contains :

# StyledFileInput
# coding: utf-8

from django.forms.widgets import FileInput
from django.utils.html import format_html
from django.forms.utils import flatatt

class StyledFileInput(FileInput):

class Media:
css = { 'all': ('styledfileinput.css', ) }
js = ('styledfileinput.js', )

def render(self, name, value, attrs=None):
if value is None:
value = ''
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
if value != '':
# Only add the 'value' attribute if a value is non-empty.
final_attrs['value'] = force_text(self._format_value(value))
return format_html(
'<div class="input-group">\n'
+ '<span class="input-group-btn">\n'
+ '<span class="btn btn-default btn-file">\n'
+ 'Browse... \n'
+ '<input multiple="" {} >\n'
+ '</span>\n'
+ '</span>\n'
+ '<input class="form-control" readonly="" type="text">\n'
+ '</div>\n', flatatt(final_attrs)
)

I’ve created a StyledFileInput class inheriting from FileInput, and redefined the render function with the whole HTML block. I’ve kept the attributes and value handling, so that Django can use it properly.

There is an inner Media class to define the required static files. This two files are placed in the static directory of my app.

Here is the content of styledfileinput.css :

/* file buttons should be styled */
.btn-file {
position: relative;
overflow: hidden;
}

.btn-file input[type=file] {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 999px;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
background: red;
cursor: inherit;
display: block;
}

Then styledfileinput.js :

(function($){
$(document)
.on('change', '.btn-file :file', function() {
var input = $(this),
numFiles = input.get(0).files ? input.get(0).files.length : 1,
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
input.trigger('fileselect', [numFiles, label]);
});

$(document).ready( function() {
$('.btn-file :file').on('fileselect', function(event, numFiles, label) {

var input = $(this).parents('.input-group').find(':text'),
log = numFiles > 1 ? numFiles + ' files selected' : label;

if( input.length ) {
input.val(log);
} else {
if( log ) alert(log);
}

});
});
})(django.jQuery);

You can see that this code is wrapped in a function called with django.jQuery for $. This is necessary as I also use the AdminDateWidget, which uses the following JavaScript :

/* Puts the included jQuery into our own namespace using noConflict and passing
* it 'true'. This ensures that the included jQuery doesn't pollute the global
* namespace (i.e. this preserves pre-existing values for both window.$ and
* window.jQuery).
*/
var django = django || {};
django.jQuery = jQuery.noConflict(true);

Using the widget

Now I can use it in a Django form :

from app.widgets.styledfileinput import StyledFileInput

class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = "__all__"
widgets = {
'date': admin.widgets.AdminDateWidget(),
'filename' : StyledFileInput(),
}

In the template, nothing changes in the form itself :

<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="panel panel-default">
<div class="panel-body">
{{ doc_form|bootstrap_horizontal }}
<button class="btn btn-default" type="submit">Envoyer</button>
</div>
</div>
</form>

You just have to be sure to put somewhere in your template {{ doc_form.media }} so that the required static files are included.

Conclusion

Now that the Bootstrap file input is redefined as a widget, it’s easy to attach to any classic Django forms, and it’s easy to reuse in any project.

If you have any suggestion to improve it, feel free to comment.