1.. _styleguide:
2
3Translate Styleguide
4====================
5
6The Translate styleguide is the styleguide for all Translate projects,
7including Translate Toolkit, Pootle, Virtaal and others.  Patches are required
8to follow these guidelines.
9
10This Styleguide follows :pep:`8` with some clarifications. It is based almost
11verbatim on the `Flask Styleguide`_.
12
13pre-commit hooks
14----------------
15
16The Translate styleguide can be checked by `pre-commit`_. The Translate toolkit
17repository repository contains configuration for it to verify the committed
18files are sane. After installing it (it is already included in the
19:file:`requirements/dev.txt`) turn it on by running ``pre-commit install`` in
20Translate toolkit checkout. This way all your changes will be automatically
21checked.
22
23You can also trigger check manually, to check all files run:
24
25.. code-block:: sh
26
27    pre-commit run --all
28
29.. _pre-commit: https://pre-commit.com/
30
31.. _styleguide-python:
32
33Python
34------
35
36These are the Translate conventions for Python coding style.
37
38.. _styleguide-general:
39
40General
41^^^^^^^
42
43Indentation
44~~~~~~~~~~~
45
464 real spaces, no tabs. Exceptions: modules that have been copied into the
47source that don't follow this guideline.
48
49
50Maximum line length
51~~~~~~~~~~~~~~~~~~~
52
5379 characters with a soft limit for 84 if absolutely necessary. Try to avoid
54too nested code by cleverly placing `break`, `continue` and `return`
55statements.
56
57
58Continuing long statements
59~~~~~~~~~~~~~~~~~~~~~~~~~~
60
61To continue a statement you can use backslashes (preceded by a space) in which
62case you should align the next line with the last dot or equal sign, or indent
63four spaces:
64
65.. code-block:: python
66
67    MyModel.query.filter(MyModel.scalar > 120) \
68                 .order_by(MyModel.name.desc()) \
69                 .limit(10)
70
71    my_long_assignment = MyModel.query.filter(MyModel.scalar > 120) \
72                         .order_by(MyModel.name.desc()) \
73                         .limit(10)
74
75    this_is_a_very_long(function_call, 'with many parameters') \
76        .that_returns_an_object_with_an_attribute
77
78
79If you break in a statement with parentheses or braces, align to the braces:
80
81.. code-block:: python
82
83    this_is_a_very_long(function_call, 'with many parameters',
84                        23, 42, 'and even more')
85
86
87If you need to break long strings, on function calls or when assigning to
88variables, try to use implicit string continuation:
89
90.. code-block:: python
91
92    this_holds_a_very_long_string("Very long string with a lot of characters "
93                                  "and words on it, so many that it is "
94                                  "necessary to break it in several lines to "
95                                  "improve readability.")
96    long_string_var = ("Very long string with a lot of characters and words on "
97                       "it, so many that it is necessary to break it in "
98                       "several lines to improve readability.")
99
100
101For lists or tuples with many items, break immediately after the opening brace:
102
103.. code-block:: python
104
105    items = [
106        'this is the first', 'set of items', 'with more items',
107        'to come in this line', 'like this'
108    ]
109
110
111Blank lines
112~~~~~~~~~~~
113
114Top level functions and classes are separated by two lines, everything else
115by one. Do not use too many blank lines to separate logical segments in code.
116Example:
117
118.. code-block:: python
119
120    def hello(name):
121        print('Hello %s!' % name)
122
123
124    def goodbye(name):
125        print('See you %s.' % name)
126
127
128    class MyClass:
129        """This is a simple docstring"""
130
131        def __init__(self, name):
132            self.name = name
133
134        @property
135        def annoying_name(self):
136            return self.name.upper() + '!!!!111'
137
138
139Strings
140~~~~~~~
141
142- Double quotes are suggested over single quotes, but always try to respect the
143  surrounding coding style. This is overruled by escaping which you should always
144  try to avoid.
145
146  .. code-block:: python
147
148    # Good.
149    str1 = "Sauron's eye"
150    str2 = 'Its name is "Virtaal".'
151
152
153    # Bad.
154    str3 = 'Sauron\'s eye'
155    str4 = "Its name is \"Virtaal\"."
156
157
158String formatting
159~~~~~~~~~~~~~~~~~
160
161While str.format() is more powerful than %-formatting, the latter has been the
162canonical way of formatting strings in Python for a long time and the Python
163core team has shown no desire to settle on one syntax over the other.
164For simple, serial positional cases (non-translatable strings), the old "%s"
165way of formatting is preferred.
166For anything more complex, including translatable strings, str.format is
167preferred as it is significantly more powerful and often cleaner.
168
169.. code-block:: python
170
171    # Good
172    print("Hello, {thing}".format(thing="world"))
173    print("Hello, {}".format("world"))
174    print("%s=%r" % ("hello", "world"))  # non-translatable strings
175
176    # Bad
177    print("%s, %s" % ("Hello", "world"))  # Translatable string.
178    print("Hello, %(thing)s" % {"thing": "world"})  # Use {thing}.
179
180
181.. _styleguide-imports:
182
183Imports
184~~~~~~~
185
186Like in :pep:`8`, but:
187
188- Imports should be grouped in the following order:
189
190  1) __future__ library imports
191  2) Python standard library imports
192  3) Third party libraries imports
193  4) Translate Toolkit imports
194  5) Current package imports, using explicit relative imports (See `PEP 328
195     <http://www.python.org/dev/peps/pep-0328/#guido-s-decision>`_)
196
197- A blank line must be present between each group of imports (like in PEP8).
198- Imports on each group must be arranged alphabetically by module name:
199
200  - Shortest module names must be before longer ones:
201    ``from django.db import ...`` before ``from django.db.models import ...``.
202
203- ``import ...`` calls must precede ``from ... import`` ones on each group:
204
205  - On each of these subgroups the entries should be alphabetically arranged.
206  - No blank lines between subgroups.
207
208- On ``from ... import``
209
210  - Use a ``CONSTANT``, ``Class``, ``function`` order, where the constants,
211    classes and functions are in alphabetical order inside of its respective
212    groups.
213  - If the import line exceeds the 80 chars, then split it using parentheses to
214    continue the import on the next line (aligning the imported items with the
215    opening parenthesis).
216
217.. code-block:: python
218
219    from __future__ import absolute_import
220
221    import re
222    import sys.path as sys_path
223    import time
224    from datetime import timedelta
225    from os import path
226
227    from lxml.html import fromstring
228
229    from translate.filters import checks
230    from translate.storage import base
231    from translate.storage.aresource import (EOF, WHITESPACE, AndroidFile,
232                                             AndroidUnit, android_decode,
233                                             android_encode)
234
235    from . import php2po
236
237
238Properties
239~~~~~~~~~~
240
241- Never use ``lambda`` functions:
242
243  .. code-block:: python
244
245    # Good.
246    @property
247    def stores(self):
248      return self.child.stores
249
250
251    # Bad.
252    stores = property(lambda self: self.child.stores)
253
254
255- Try to use ``@property`` instead of ``get_*`` or ``is_*`` methods that don't
256  require passing any parameter:
257
258  .. code-block:: python
259
260    # Good.
261    @property
262    def terminology(self):
263      ...
264
265    @property
266    def is_monolingual(self):
267      ...
268
269
270    # Also good.
271    def get_stores_for_language(self, language):
272      ...
273
274
275    # Bad.
276    def get_terminology(self):
277      ...
278
279    def is_monolingual(self):
280      ...
281
282
283- Always use ``@property`` instead of ``property(...)``, even for properties
284  that also have a setter or a deleter:
285
286  .. code-block:: python
287
288    # Good.
289    @property
290    def units(self):
291      ...
292
293
294    # Also good.
295    @property
296    def x(self):
297      """I'm the 'x' property."""
298      return self._x
299
300    @x.setter
301    def x(self, value):  # Note: Method must be named 'x' too.
302      self._x = value
303
304    @x.deleter
305    def x(self):  # Note: Method must be named 'x' too.
306      del self._x
307
308
309    # Bad.
310    def _get_units(self):
311      ...
312    units = property(_get_units)
313
314
315    # Also bad.
316    def getx(self):
317      return self._x
318    def setx(self, value):
319      self._x = value
320    def delx(self):
321      del self._x
322    x = property(getx, setx, delx, "I'm the 'x' property.")
323
324
325Expressions and Statements
326^^^^^^^^^^^^^^^^^^^^^^^^^^
327
328General whitespace rules
329~~~~~~~~~~~~~~~~~~~~~~~~
330
331- No whitespace for unary operators that are not words (e.g.: ``-``, ``~``
332  etc.) as well on the inner side of parentheses.
333- Whitespace is placed between binary operators.
334
335.. code-block:: python
336
337    # Good.
338    exp = -1.05
339    value = (item_value / item_count) * offset / exp
340    value = my_list[index]
341    value = my_dict['key']
342
343
344    # Bad.
345    exp = - 1.05
346    value = ( item_value / item_count ) * offset / exp
347    value = (item_value/item_count)*offset/exp
348    value=( item_value/item_count ) * offset/exp
349    value = my_list[ index ]
350    value = my_dict ['key']
351
352
353Slice notation
354~~~~~~~~~~~~~~
355
356While :pep:`8` calls for spaces around operators ``a = b + c`` this results in
357flags when you use ``a[b+1:c-1]`` but would allow the rather unreadable
358``a[b + 1:c - 1]`` to pass. :pep:`8` is rather quiet on slice notation.
359
360- Don't use spaces with simple variables or numbers
361- Use brackets for expressions with spaces between binary operators
362
363  .. code-block:: python
364
365    # Good.
366    a[1:2]
367    a[start:end]
368    a[(start - 1):(end + var + 2)]  # Brackets help group things and don't hide the slice
369    a[-1:(end + 1)]
370
371
372    # Bad.
373    a[start: end]  # No spaces around :
374    a[start-1:end+var+2]  # Insanely hard to read, especially when your expressions are more complex
375    a[start - 1:end + 2]  # You lose sight of the fact that it is a slice
376    a[- 1:end]  # -1 is unary, no space
377
378
379.. note::
380
381   String slice formatting is still under discussion.
382
383Comparisons
384~~~~~~~~~~~
385
386- Against arbitrary types: ``==`` and ``!=``
387- Against singletons with ``is`` and ``is not`` (e.g.: ``foo is not None``)
388- Never compare something with `True` or `False` (for example never do ``foo ==
389  False``, do ``not foo`` instead)
390
391
392Negated containment checks
393~~~~~~~~~~~~~~~~~~~~~~~~~~
394
395- Use ``foo not in bar`` instead of ``not foo in bar``
396
397
398Instance checks
399~~~~~~~~~~~~~~~
400
401- ``isinstance(a, C)`` instead of ``type(A) is C``, but try to avoid instance
402  checks in general.  Check for features.
403
404
405If statements
406~~~~~~~~~~~~~
407
408- Use ``()`` brackets around complex if statements to allow easy wrapping,
409  don't use backslash to wrap an if statement.
410- Wrap between ``and``, ``or``, etc.
411- Keep ``not`` with the expression
412- Use ``()`` alignment between expressions
413- Use extra ``()`` to eliminate ambiguity, don't rely on an understanding of
414  Python operator precedence rules.
415
416  .. code-block:: python
417
418    # Good.
419    if length >= (upper + 2):
420        ...
421
422    if (length >= 25 and
423        string != "Something" and
424        not careful):
425        do_something()
426
427
428    # Bad.
429    if length >= upper + 2:
430        ...
431
432    if (length...
433        and string !=...
434
435
436Naming Conventions
437^^^^^^^^^^^^^^^^^^
438
439.. note::
440
441   This has not been implemented or discussed.  The Translate code
442   is not at all consistent with these conventions.
443
444
445- Class names: ``CamelCase``, with acronyms kept uppercase (``HTTPWriter`` and
446  not ``HttpWriter``)
447- Variable names: ``lowercase_with_underscores``
448- Method and function names: ``lowercase_with_underscores``
449- Constants: ``UPPERCASE_WITH_UNDERSCORES``
450- precompiled regular expressions: ``name_re``
451
452Protected members are prefixed with a single underscore.  Double underscores
453are reserved for mixin classes.
454
455To prevent name clashes with keywords, one trailing underscore may be appended.
456Clashes with builtins are allowed and **must not** be resolved by appending an
457underline to the name.  If your code needs to access a shadowed builtin, rebind
458the builtin to a different name instead.  Consider using a different name to
459avoid having to deal with either type of name clash, but don't complicate names
460with prefixes or suffixes.
461
462
463Function and method arguments
464~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
465
466- Class methods: ``cls`` as first parameter
467- Instance methods: ``self`` as first parameter
468
469
470.. _styleguide-docs:
471
472Documentation
473=============
474
475We use Sphinx_ to generate our API and user documentation. Read the
476`reStructuredText primer`_ and `Sphinx documentation`_ as needed.
477
478
479Special roles
480-------------
481
482We introduce a number of special roles for documentation:
483
484* ``:issue:`` -- links to a toolkit issue Github.
485
486  * ``:issue:`234``` gives: :issue:`234`
487  * ``:issue:`broken <234>``` gives: :issue:`broken <234>`
488
489* ``:opt:`` -- mark command options and command values.
490
491  * ``:opt:`-P``` gives :opt:`-P`
492  * ``:opt:`--progress=dots``` gives :opt:`--progress=dots`
493  * ``:opt:`dots``` gives :opt:`dots`
494
495* ``:man:`` -- link to a Linux man page.
496
497  * ``:man:`msgfmt``` gives :man:`msgfmt`
498
499
500Code and command line highlighting
501----------------------------------
502
503All code examples and format snippets should be highlighted to make them easier
504to read.  By default Sphinx uses Python highlighting of code snippets (but it
505doesn't always work).  You will want to change that in these situations:
506
507.. highlight:: rest
508
509* The examples are not Python e.g. talking about INI file parsing.  In which
510  case set the file level highlighting using::
511
512     .. highlight:: ini
513
514* There are multiple different code examples in the document, then use::
515
516    .. code-block:: ruby
517
518  before each code block.
519
520* Python code highlighting isn't working, then force Python highlighting using::
521
522    .. code-block:: python
523
524.. note:: Generally we prefer explicit markup as this makes it easier for those
525   following you to know what you intended.  So use ``.. code-block:: python``
526   even though in some cases this is not required.
527
528With *command line examples*, to improve readability use::
529
530    .. code-block:: console
531
532Add ``$`` command prompt markers and ``#`` comments as required, as shown in
533this example:
534
535.. code-block:: console
536
537   $ cd docs
538   $ make html  # Build all Sphinx documentation
539   $ make linkcheck  # Report broken links
540
541
542.. highlight:: python
543
544
545User documentation
546------------------
547
548This is documentation found in ``docs/`` and that is published on Read the
549Docs. The target is the end user so our primary objective is to make accessible,
550readable and beautiful documents for them.
551
552
553Docstrings
554----------
555
556Docstring conventions:
557  All docstrings are formatted with reStructuredText as understood by
558  Sphinx.  Depending on the number of lines in the docstring, they are
559  laid out differently.  If it's just one line, the closing triple
560  quote is on the same line as the opening, otherwise the text is on
561  the same line as the opening quote and the triple quote that closes
562  the string on its own line:
563
564  .. code-block:: python
565
566    def foo():
567        """This is a simple docstring."""
568
569
570    def bar():
571        """This is a longer docstring with so much information in there
572        that it spans three lines.  In this case the closing triple quote
573        is on its own line.
574        """
575
576
577Please read :pep:`257` (Docstring Conventions) for a general overview,
578the important parts though are:
579
580- A docstring should have a brief one-line summary, ending with a period. Use
581  ``Do this``, ``Return that`` rather than ``Does ...``, ``Returns ...``.
582- If there are more details there should be a blank line between the one-line
583  summary and the rest of the text.  Use paragraphs and formatting as needed.
584- Use `reST field lists`_ to describe the input parameters and/or return types
585  as the last part of the docstring.
586- Use proper capitalisation and punctuation.
587- Don't restate things that would appear in parameter descriptions.
588
589.. code-block:: python
590
591    def addunit(self, unit):
592        """Append the given unit to the object's list of units.
593
594        This method should always be used rather than trying to modify the
595        list manually.
596
597        :param Unit unit: Any object that inherits from :class:`Unit`.
598        """
599        self.units.append(unit)
600
601
602Parameter documentation:
603  Document parameters using `reST field lists`_ as follows:
604
605  .. code-block:: python
606
607    def foo(bar):
608        """Simple docstring.
609
610        :param SomeType bar: Something
611        :return: Returns something
612        :rtype: Return type
613        """
614
615
616Cross referencing code:
617   When talking about other objects, methods, functions and variables
618   it is good practice to cross-reference them with Sphinx's `Python
619   cross-referencing`_.
620
621Other directives:
622   Use `paragraph-level markup`_ when needed.
623
624.. note::
625
626   We still need to gather the useful ones that we want you to use and how to use
627   them.  E.g. how to talk about a parameter in the docstring.  How to reference
628   classes in the module.  How to reference other modules, etc.
629
630
631Module header:
632  The module header consists of a utf-8 encoding declaration, copyright
633  attribution, license block and a standard docstring:
634
635  .. code-block:: python
636
637    #
638    ... LICENSE BLOCK...
639
640    """A brief description"""
641
642..    """
643        package.module
644        ~~~~~~~~~~~~~~
645
646..        A brief description goes here.
647
648..        :copyright: (c) YEAR by AUTHOR.
649        :license: LICENSE_NAME, see LICENSE_FILE for more details.
650    """
651
652Deprecation:
653  Document the deprecation and version when deprecating features:
654
655  .. code-block:: python
656
657     from translate.misc.deprecation import deprecated
658
659
660     @deprecated("Use util.run_fast() instead.")
661     def run_slow():
662         """Run fast
663
664         .. deprecated:: 1.5
665            Use :func:`run_fast` instead.
666         """
667         run_fast()
668
669
670
671Comments
672--------
673
674General:
675  - The ``#`` symbol (pound or hash) is used to start comments.
676  - A space must follow the ``#`` between any written text.
677  - Line length must be observed.
678  - Inline comments are preceded by two spaces.
679  - Write sentences correctly: proper capitalisation and punctuation.
680
681  .. code-block:: python
682
683    # Good comment with space before and full sentence.
684    statement  # Good comment with two spaces
685
686
687    #Bad comment no space before
688    statement # Bad comment, needs two spaces
689
690
691Docstring comments:
692  Rules for comments are similar to docstrings.  Both are formatted with
693  reStructuredText.  If a comment is used to document an attribute, put a
694  colon after the opening pound sign (``#``):
695
696  .. code-block:: python
697
698    class User:
699        #: the name of the user as unicode string
700        name = Column(String)
701        #: the sha1 hash of the password + inline salt
702        pw_hash = Column(String)
703
704
705.. _Flask Styleguide: http://flask.pocoo.org/docs/styleguide/
706.. _reST field lists: http://sphinx-doc.org/domains.html#info-field-lists
707.. _Python cross-referencing: http://sphinx-doc.org/domains.html#cross-referencing-python-objects
708.. _Sphinx: http://sphinx-doc.org/
709.. _reStructuredText primer: http://sphinx-doc.org/rest.html
710.. _Sphinx documentation: http://sphinx-doc.org/contents.html
711.. _paragraph-level markup: http://sphinx-doc.org/markup/para.html#paragraph-level-markup
712