summaryrefslogtreecommitdiff
blob: 5f15e1590a481ebf7f5548a449facc96270f5546 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
Code Guidelines
---------------
A few code guidelines to try to stick to, please comment if none of these make
sense, they are pretty basic and mostly apply to old code.  However for people
who are looking at current code, they make take up bad habits that exist in the
current codebase.

Python Version
--------------

Python 2.6 is the minimum supported version, since it is the first version to
support Python 3 syntax. All exception handling should use Python 3 'except'
syntax, and the print function should be used instead of Python 2's print
statement (from __future__ import print_function).

Dependencies
------------

Python and Bash should be the only hard dependencies. Any other dependencies,
including external Python modules that are not included with Python itself,
must be optionally enabled by run-time detection.

Tabs
----

The current code uses tabs, not spaces.  Keep whitespace usage consistent
between files.  New files should use tabs.

Line-Wrapping
-------------

Lines should typically not be longer than 80 characters; if they are an attempt
should be made to wrap them.  Move code to the line below and indent once (\t).

errors.append(MalformedMetadata(
	errors.DESCRIPTION_TOO_LONG_ERROR % \
	(length, max_desc_len),
	attr='DESCRIPTION.toolong')

Do not do this:

errors.append(MalformedMetadata(
              errors.DESCRIPTION_TOO_LONG_ERROR % \
              (length, max_desc_len),
              attr='DESCRIPTION.toolong')

The mixing of tabs and spaces means other developers can't read what you did.
This is why the python peps state spaces over tabs; because with spaces the line
wrapping is always clear (but you cannot convert spaces as easily as tabwidth).

Comparisons
-----------

if foo != None

should be replaced with:

if foo is not None:

Is not does a reference comparison (address1 = address2 basically) and 
the == forces a by value compare (with __eq__())

Dict Lookups
------------

Try not to use has_key, you can use

if foo in dict

instead of if dict.has_key(foo)

Also don't do stuff like:

if foo in dict and dict[foo]:

Generally you can do two things here, if you are messing with defaults..

dict.get(foo, some_default)

will try to retrieve foo from dict, if there is a KeyError, will insert foo
into dict with the value of some_default.  This method is preferred in cases where
you are messing with defaults:

try:
	dict[foo]
except KeyError:
	dict[foo] = default_value

The get call is nicer (compact) and faster (try,except are slow).

Exceptions
----------

Don't use the format raise Exception, "string"
It will be removed in py3k.

YES:
  raise KeyError("No key")

NO:
  raise KeyError, "No key"

Imports
-------

Import things one per line

YES:
  import os
  import time
  import sys

NO:
  import os,sys,time

When importing from a module, you may import more than 1 thing at a time.

YES:
  from portage.module import foo, bar, baz

Multiline imports are ok (for now :))

Try to group system and package imports separately.

YES:
  import os
  import sys
  import time

  from portage.locks import lockfile
  from portage.versions import vercmp

NO:
  import os
  import portage
  import portage.util
  import time
  import sys

Try not to import large numbers of things into the namespace of a module.
I realize this is done all over the place in current code but it really makes it
a pain to do code reflection when the namespace is cluttered with identifiers 
from other modules.

YES:

from portage import output

NO:

from portage.output import bold, create_color_func, darkgreen, \
  green, nocolor, red, turquoise, yellow

The YES example imports the 'output' module into the current namespace.
The negative here is having to use output.COLOR all over the place instead of
just COLOR.  However it means during introspection of the current namespace
'green','red', 'yellow', etc. will not show up.

The NO example just imports a set of functions from the output module.  It is
somewhat annoying because the import line needs to be modified when functions
are needed and often unused functions are left in the import line until someone
comes along with a linter to clean up (does not happen often).