1
0

style.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. .. _coding-style:
  2. =================
  3. Salt Coding Style
  4. =================
  5. Salt is developed with a certain coding style, while the style is dominantly
  6. PEP 8 it is not completely PEP 8. It is also noteworthy that a few
  7. development techniques are also employed which should be adhered to. In the
  8. end, the code is made to be "Salty".
  9. Most importantly though, we will accept code that violates the coding style and
  10. KINDLY ask the contributor to fix it, or go ahead and fix the code on behalf of
  11. the contributor. Coding style is NEVER grounds to reject code contributions,
  12. and is never grounds to talk down to another member of the community (There are
  13. no grounds to treat others without respect, especially people working to
  14. improve Salt)!!
  15. .. _pylint-instructions:
  16. Linting
  17. =======
  18. Most Salt style conventions are codified in Salt's ``.testing.pylintrc`` file.
  19. Salt's pylint file has two dependencies: pylint_ and saltpylint_. You can
  20. install these dependencies with ``pip``:
  21. .. code-block:: bash
  22. pip install pylint
  23. pip install saltpylint
  24. The ``.testing.pylintrc`` file is found in the root of the Salt project and can
  25. be passed as an argument to the pylint_ program as follows:
  26. .. code-block:: bash
  27. pylint --rcfile=/path/to/salt/.testing.pylintrc salt/dir/to/lint
  28. .. note::
  29. There are two pylint files in the ``salt`` directory. One is the
  30. ``.pylintrc`` file and the other is the ``.testing.pylintrc`` file. The
  31. tests that run in Jenkins against GitHub Pull Requests use
  32. ``.testing.pylintrc``. The ``testing.pylintrc`` file is a little less
  33. strict than the ``.pylintrc`` and is used to make it easier for contributors
  34. to submit changes. The ``.pylintrc`` file can be used for linting, but the
  35. ``testing.pylintrc`` is the source of truth when submitting pull requests.
  36. .. _pylint: http://www.pylint.org
  37. .. _saltpylint: https://github.com/saltstack/salt-pylint
  38. Variables
  39. =========
  40. Variables should be a minimum of three characters and should provide an
  41. easy-to-understand name of the object being represented.
  42. When keys and values are iterated over, descriptive names should be used
  43. to represent the temporary variables.
  44. Multi-word variables should be separated by an underscore.
  45. Variables which are two-letter words should have an underscore appended
  46. to them to pad them to three characters.
  47. Strings
  48. =======
  49. Salt follows a few rules when formatting strings:
  50. Single Quotes
  51. -------------
  52. In Salt, all strings use single quotes unless there is a good reason not to.
  53. This means that docstrings use single quotes, standard strings use single
  54. quotes etc.:
  55. .. code-block:: python
  56. def foo():
  57. '''
  58. A function that does things
  59. '''
  60. name = 'A name'
  61. return name
  62. Formatting Strings
  63. ------------------
  64. All strings which require formatting should use the `.format` string method:
  65. .. code-block:: python
  66. data = 'some text'
  67. more = '{0} and then some'.format(data)
  68. Make sure to use indices or identifiers in the format brackets, since empty
  69. brackets are not supported by python 2.6.
  70. Please do NOT use printf formatting.
  71. Docstring Conventions
  72. ---------------------
  73. Docstrings should always add a newline, docutils takes care of the new line and
  74. it makes the code cleaner and more vertical:
  75. `GOOD`:
  76. .. code-block:: python
  77. def bar():
  78. '''
  79. Here lies a docstring with a newline after the quotes and is the salty
  80. way to handle it! Vertical code is the way to go!
  81. '''
  82. return
  83. `BAD`:
  84. .. code-block:: python
  85. def baz():
  86. '''This is not ok!'''
  87. return
  88. When adding a new function or state, where possible try to use a
  89. ``versionadded`` directive to denote when the function or state was added.
  90. .. code-block:: python
  91. def new_func(msg=''):
  92. '''
  93. .. versionadded:: 0.16.0
  94. Prints what was passed to the function.
  95. msg : None
  96. The string to be printed.
  97. '''
  98. print msg
  99. If you are uncertain what version should be used, either consult a core
  100. developer in IRC or bring this up when opening your
  101. :ref:`pull request <installing-for-development>` and a core developer will add the proper
  102. version once your pull request has been merged. Bugfixes will be available in a
  103. bugfix release (i.e. 0.17.1, the first bugfix release for 0.17.0), while new
  104. features are held for feature releases, and this will affect what version
  105. number should be used in the ``versionadded`` directive.
  106. Similar to the above, when an existing function or state is modified (for
  107. example, when an argument is added), then under the explanation of that new
  108. argument a ``versionadded`` directive should be used to note the version in
  109. which the new argument was added. If an argument's function changes
  110. significantly, the ``versionchanged`` directive can be used to clarify this:
  111. .. code-block:: python
  112. def new_func(msg='', signature=''):
  113. '''
  114. .. versionadded:: 0.16.0
  115. Prints what was passed to the function.
  116. msg : None
  117. The string to be printed. Will be prepended with 'Greetings! '.
  118. .. versionchanged:: 0.17.1
  119. signature : None
  120. An optional signature.
  121. .. versionadded 0.17.0
  122. '''
  123. print 'Greetings! {0}\n\n{1}'.format(msg, signature)
  124. Dictionaries
  125. ============
  126. Dictionaries should be initialized using `{}` instead of `dict()`.
  127. See here_ for an in-depth discussion of this topic.
  128. .. _here: http://doughellmann.com/2012/11/12/the-performance-impact-of-using-dict-instead-of-in-cpython-2-7-2.html
  129. Imports
  130. =======
  131. Salt code prefers importing modules and not explicit functions. This is both a
  132. style and functional preference. The functional preference originates around
  133. the fact that the module import system used by pluggable modules will include
  134. callable objects (functions) that exist in the direct module namespace. This
  135. is not only messy, but may unintentionally expose code python libs to the Salt
  136. interface and pose a security problem.
  137. To say this more directly with an example, this is `GOOD`:
  138. .. code-block:: python
  139. import os
  140. def minion_path():
  141. path = os.path.join(self.opts['cachedir'], 'minions')
  142. return path
  143. This on the other hand is `DISCOURAGED`:
  144. .. code-block:: python
  145. from os.path import join
  146. def minion_path():
  147. path = join(self.opts['cachedir'], 'minions')
  148. return path
  149. The time when this is changed is for importing exceptions, generally directly
  150. importing exceptions is preferred:
  151. This is a good way to import exceptions:
  152. .. code-block:: python
  153. from salt.exceptions import CommandExecutionError
  154. Absolute Imports
  155. ----------------
  156. Although `absolute imports`_ seems like an awesome idea, please do not use it.
  157. Extra care would be necessary all over salt's code in order for absolute
  158. imports to work as supposed. Believe it, it has been tried before and, as a
  159. tried example, by renaming ``salt.modules.sysmod`` to ``salt.modules.sys``, all
  160. other salt modules which needed to import :mod:`sys<python2:sys>` would have to
  161. also import :mod:`absolute_import<python2:__future__>`, which should be
  162. avoided.
  163. .. note::
  164. An exception to this rule is the ``absolute_import`` from ``__future__`` at
  165. the top of each file within the Salt project. This import is necessary for
  166. Py3 compatibility. This particular import looks like this:
  167. .. code-block:: python
  168. from __future__ import absolute_import
  169. This import is required for all new Salt files and is a good idea to add to
  170. any custom states or modules. However, the practice of avoiding absolute
  171. imports still applies to all other cases as to avoid a name conflict.
  172. .. _`absolute imports`: http://legacy.python.org/dev/peps/pep-0328/#rationale-for-absolute-imports
  173. Vertical is Better
  174. ==================
  175. When writing Salt code, vertical code is generally preferred. This is not a hard
  176. rule but more of a guideline. As PEP 8 specifies, Salt code should not exceed 79
  177. characters on a line, but it is preferred to separate code out into more
  178. newlines in some cases for better readability:
  179. .. code-block:: python
  180. import os
  181. os.chmod(
  182. os.path.join(self.opts['sock_dir'],
  183. 'minion_event_pub.ipc'),
  184. 448
  185. )
  186. Where there are more line breaks, this is also apparent when constructing a
  187. function with many arguments, something very common in state functions for
  188. instance:
  189. .. code-block:: python
  190. def managed(name,
  191. source=None,
  192. source_hash='',
  193. user=None,
  194. group=None,
  195. mode=None,
  196. template=None,
  197. makedirs=False,
  198. context=None,
  199. replace=True,
  200. defaults=None,
  201. saltenv=None,
  202. backup='',
  203. **kwargs):
  204. .. note::
  205. Making function and class definitions vertical is only required if the
  206. arguments are longer then 80 characters. Otherwise, the formatting is
  207. optional and both are acceptable.
  208. Line Length
  209. -----------
  210. For function definitions and function calls, Salt adheres to the PEP-8
  211. specification of at most 80 characters per line.
  212. Non function definitions or function calls, please adopt a soft limit of 120
  213. characters per line. If breaking the line reduces the code readability, don't
  214. break it. Still, try to avoid passing that 120 characters limit and remember,
  215. **vertical is better... unless it isn't**
  216. Indenting
  217. =========
  218. Some confusion exists in the python world about indenting things like function
  219. calls, the above examples use 8 spaces when indenting comma-delimited
  220. constructs.
  221. The confusion arises because the pep8 program INCORRECTLY flags this as wrong,
  222. where PEP 8, the document, cites only using 4 spaces here as wrong, as it
  223. doesn't differentiate from a new indent level.
  224. Right:
  225. .. code-block:: python
  226. def managed(name,
  227. source=None,
  228. source_hash='',
  229. user=None)
  230. WRONG:
  231. .. code-block:: python
  232. def managed(name,
  233. source=None,
  234. source_hash='',
  235. user=None)
  236. Lining up the indent is also correct:
  237. .. code-block:: python
  238. def managed(name,
  239. source=None,
  240. source_hash='',
  241. user=None)
  242. This also applies to function calls and other hanging indents.
  243. pep8 and Flake8 (and, by extension, the vim plugin Syntastic) will complain
  244. about the double indent for hanging indents. This is a `known conflict
  245. <https://github.com/jcrocholl/pep8/issues/167#issuecomment-15936564>`_ between
  246. pep8 (the script) and the actual PEP 8 standard. It is recommended that this
  247. particular warning be ignored with the following lines in
  248. ``~/.config/flake8``:
  249. .. code-block:: ini
  250. [flake8]
  251. ignore = E226,E241,E242,E126
  252. Make sure your Flake8/pep8 are up to date. The first three errors are ignored
  253. by default and are present here to keep the behavior the same. This will also
  254. work for pep8 without the Flake8 wrapper -- just replace all instances of
  255. 'flake8' with 'pep8', including the filename.
  256. Code Churn
  257. ==========
  258. Many pull requests have been submitted that only churn code in the name of
  259. PEP 8. Code churn is a leading source of bugs and is strongly discouraged.
  260. While style fixes are encouraged they should be isolated to a single file per
  261. commit, and the changes should be legitimate, if there are any questions about
  262. whether a style change is legitimate please reference this document and the
  263. official PEP 8 (http://legacy.python.org/dev/peps/pep-0008/) document before
  264. changing code. Many claims that a change is PEP 8 have been invalid, please
  265. double check before committing fixes.