Skip to content

ulamlabs/python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 

Repository files navigation

Python Style Guide

Table of Contents

  1. Inports
  2. Indentation
  3. Techniques

Inports

  • 1.1 Split imports into 3 categories (stdlib, 3rdparty, internal imports), relative imports should be the last. Try to keep them sorted.

    import datetime import logging from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django.conf import settings from django_states.machine import StateMachine, StateDefinition, StateGroup, StateTransition from django_states.exceptions import TransitionValidationError from ourapp.notifications.handlers import NOTIFICATION_METHOD from ourapp.notifications import notifiers from ourapp.module_a.provider import Trusted from ourapp.activation.models import XOrder from ourapp.porting.utils import get_closest_wish_date from .models import Inport from .utils import add_inport_s3

  • 1.2 Use imports for packages and modules only, if it is possible.

    import datetime # never: from datetime import datetime or similar import logging # never: from logging import getLogger import mock # never from mock import Mock import random import uuid import bson # never from bson import ObjectId from django.utils import timezone # never: from django.utils.timezone import now

  • 1.3 If import exceeded line length limit, format it like that:

    from ourapp.porting.tasks import ( task_a, task_b, task_c, # <- comma here )

Indentation

  • 2.1 function calls

    abc = qwe(dsadsa(product.to_dict(), cls=DecimalEncoder, mimetype='application/json')) # bad abc = qwe(dsadsa(product.to_dict(), cls=DecimalEncoder, mimetype='application/json')) # bad abc = qwe(dsadsa(product.to_dict(), cls=DecimalEncoder, mimetype='application/json')) # bad abc = qwe(dsadsa( product.to_dict(), cls=DecimalEncoder, mimetype='application/json', # <- comma here )) # OK abc = qwe( dsadsa( product.to_dict(), cls=DecimalEncoder, mimetype='application/json', # <- comma here ) ) # could be too # especially when qwe has one aditional keyword parameter: abc = qwe( dsadsa( product.to_dict(), cls=DecimalEncoder, mimetype='application/json', # <- comma here ), # <- comma here dupa=2, # <- comma here ) # OK

  • 2.2 dict class

    # bad abc = dict(abc=2, cde=5, mama='tata', tata='mama', raz=1, dwa=2) # bad abc = dict(abc=2, cde=5, mama='tata', tata='mama', raz=1, dwa=2) # bad  abc = dict( abc=2, cde=5, mama='tata', tata='mama', raz=1, dwa=2 ) # bad abc = dict( abc=2, cde=5, mama='tata', tata='mama', raz=1, dwa=2, ) # good abc = dict( abc=2, cde=5, mama='tata', tata='mama', raz=1, dwa=2, # <- comma here ! ) 

  • 2.3 dict curly brackets

    # bad abc = {'abc': 2, 'cde': 5, 'mama': 'tata', 'tata': 'mama', 'raz': 1, 'dwa': 2} # bad abc = {'abc': 2, 'cde': 5, 'mama': 'tata', 'tata': 'mama', 'raz': 1, 'dwa': 2} # bad  abc = { 'abc': 2, 'cde': 5, 'mama': 'tata', 'tata': 'mama', 'raz': 1, 'dwa': 2 } # bad abc = { 'abc': 2, 'cde': 5, 'mama': 'tata', 'tata': 'mama', 'raz': 1, 'dwa': 2, } # good abc = { 'abc': 2, 'cde': 5, 'mama': 'tata', 'tata': 'mama', 'raz': 1, 'dwa': 2, # <- comma here ! }

  • 2.4 func call and dicts

     abc = abc({ 'a': 1, 'b': 3, 'c': 4, # <- comma here ! }) abc = abc(dict( a=1, b=2, c=3, # <- comma here ! )) nokaut_api_params = urllib.urlencode({ 'key': str(nokaut_key), 'keyword': str(keyword), 'format': 'xml', 'method': 'nokaut.Product.getByKeyword', 'sort_direction': 'price_asc', 'returnType': 'full', 'limit': '1', # <- comma here ! })

  • 2.5 list comprehension

     # bad data = [model_field for form_field, model_field in fields if form_field in form] # bad data = [model_field for form_field, model_field in fields if form_field in form ] # good data = [ model_field for form_field, model_field in fields if form_field in form ] # good (if exceeding line length limit) data = [ model_field for form_field, model_field in fields if form_field in form ]

  • 2.6 dict comprehension

     # bad data = {model_field: form[form_field].data for form_field, model_field in fields if form_field in form} # good data = { model_field: form[form_field].data for form_field, model_field in fields if form_field in form } # good (if exceeding line length limit) data = { model_field: form[form_field].data for form_field, model_field in fields if form_field in form }

  • 2.7 if statement if conditions are too long, store their result in variable with meaningful name

    # bad if abc is None and b is True and c == 'mama' \ and x != 1 or c in ('mama', 'tata') \ or babcia.age > 100: # checks if thing should be done # do something big # bad if (abc is None and b is True and c == 'mama' and x != 1 or c in ('mama', 'tata') or babcia.age > 100): # checks if thing should be done # do something big # good should_be_done = ( # no comment needed ! abc is None and b is True and c == 'mama'and x != 1 or c in ('mama', 'tata') or babcia.age > 100 ) if should_be_done: # do something big

  • 2.8 slashes never use them

    # bad: def x(): a_identity = self.aidentityconfirm_set.filter(uuid=self.id_at_provider).first() return a_identity.get_person_who_registed_y().get_full_name()\ if a_identity and a_identity.state == "confirmed" else "A identity is not confirmed yet" # good: def x(): a_identity = self.aidentityconfirm_set.filter(uuid=self.id_at_provider).first() if a_identity and a_identity.state == "confirmed": return a_identity.get_person_who_registed_y().get_full_name() else: return "A identity is not confirmed yet" # there is one exception when you can use slashes, when using chaining methods, examples: # django ORM: posts = Post.objects.filter(blog__id=x)\ .filter(created_at__gt=y)\ .filter(desc__contains=z)\ .order_by('created_at') # Google App Engine NDB greetings = Greeting.query_book(ancestor_key)\ .filter(Greeting.userid >= 40)\ .filter(Greeting.userid < 100)\ .fetch(self.GREETINGS_PER_PAGE) # SQLAlchemy files = File.query.filter(File.used.is_(False))\ .filter(File.modified < daysago2)\ .yield_per(10) # mongoalchemy place = session.query(Places).filter_by(loc=a)\ .filter(created_at=b)\ .descending('created_at').first()

  • 2.9 Single quotes vs double quotes Use double quotes around strings that are natural language messages and single quotes for small symbol-like strings, for example:

    LIGHT_MESSAGES = { 'english': "There are 3 lights.", 'pirate': "Arr! Thar be 3 lights." } def lights_message(language, number_of_lights): """Return a language-appropriate string reporting the light count.""" return LIGHT_MESSAGES[language] def is_pirate(message): """Return True if the given message sounds piratical.""" return re.search(r"(?i)(arr|avast|yohoho)!", message) is not None

    ref: http://stackoverflow.com/a/56190

Techniques

  • 3.1 Bail early is idiomatic coding style.
 # BAD, really bad def bad_method(a): b = one(a) if b.isgood(): c = two(b) if c.isok(): d = three(c) if d.hasX(): return d else: raise NoXError else: raise NotOKError # GOOD, more clear, more obvious  def good_method(a): b = one(a) if not b.isgood(): return c = two(b) if not c.isok() raise NotOKError d = three(c) if not d.hasX(): raise NoXError return d

Releases

No releases published

Packages

No packages published