Please note that some parts of the code may not follow this coding style because they have been written before or with laxity... try to respect the coding style anyway for new parts of code, and feel free to fix the existing parts.
We generally follow the PEP 8 conventions, but with some specificities.
- 4 spaces indentation (no tab)
- 2 empty lines preceding class definition
- 1 empty line preceding method definition
- files must be encoded in UTF-8
- docstrings for all classes and methods
- XEP are always referenced in the format XEP-0XXX (with 4 digits)
- do not let trailing spaces in sources
- profile/profile_key argument is always at the last position, if it need a default value, most of time C.PROF_KEY_NONE should be used
- client argument is always at the first position (except in a callback where first argument is the result, in which case it is in second position)
- class names use CamelCase
- method names use mixedCase
- variable names use lower_case_with_underscores
- abbreviations and constants use UPPERCASE
- use underscore between letter and digit (i.e. XEP_055)
- one leading underscore for internal methods and variables (methodes which should no be called from outside of the module)
- two leading underscores for private methods and variables
- one trailing underscore for methods and variables that would conflict with reserved built-in symbols
self.normal_use self._internal_use self.__private_use class_ # class is a reserved keyword
- we use "__" when a value must be ignored (double underscore), instead of the "_" (simple underscore) generally used, because _() is already used for gettext.
- Const class must be imported as C, to avoid typing too much and let the constant name more readable:
from core.constants import Const as C profile_key = C.PROF_KEY_DEFAULT
There's a specific convention to name variables representing XMPP JIDs:
- use the suffix _jid for JID instance
- use the suffix _jid_s for unicode string
Note: JID objects should be use whenever it's possible, but them sometimes need to be converted to unicode string when serialization is needed (XML, bridge, etc). Conversion has to be done as soon as the unicode JID is received, and just before serialisation. Also beware that there are two classes named JID: one defined in twisted and used in the backend, one defined in sat.tools to be used by the frontends.
- as we just said, bridge methods can not take a JID as argument, you must pass them a string representation of the JID instead... in that case, please name the bridge method self._methodCb and use it only as an intermediate to convert the string to a JID before calling the actual processing method self.methodCb. Example :
from twisted.words.protocols.jabber import client as jabber_client, jid [...] host.bridge.addMethod("findGateways", ".plugin", in_sign='ss', out_sign='s', method=self._findGatewaysCb) [...] def _findGatewaysCb(entity_jid_s, profile_key=C.PROF_KEY_DEFAULT): return self.findGatewaysCb(jid.JID(entity_jid_s), profile_key) def findGatewaysCb(entity_jid, profile_key=C.PROF_KEY_DEFAULT): [...]
Bridge methods and signals, listeners and triggers
Please append the following suffixes to methods names:
- Handler for a bridge signal handler
- Listener to a listener method
- Trigger to a method that is called by a trigger
TODO: bridge method and signal names, trigger points names and listener should follow a guideline too.
- # are always followed by a single space
- inline comments are preceded by two spaces
- see General section for XEP names
- RFC are always referenced in the format RFC XXXX, e.g. RFC 6121
- paragraph are referenced using the symbol §, e.g. RFC 6121 §5.2.2, XEP-0050 §4.4 Table 5
Please indicate the parts that deserve a special attention or some more work with a comment line starting with a special keyword:
- # XXX: important comment to understand what is done here
- # FIXME: there's some issue to be fixed, for now we use a temporary work-around
- # TODO: it is partially working but some features are not implemented yet
Here is a docstring example:
def theMethod(self, arg1, arg2, arg3, profile_key=C.PROF_KEY_NONE): """One line sentence describing the method. More infos about the method... @param arg1: description @param arg2 (tuple, list): description @param arg3 (dict): bla bla (key: unicode, value: dict) where key can be: - 'key1': description - C.KEY_CONST_NAME: description - value: bla bla where key can be: - 'toto': description - 'tata': description @param profile_key: %(doc_profile_key)s @return (D(int)): description @raise: exceptions.FeatureNotFound """
- there is no space after the """
- there is one blank after the first sentence
- you can detail more the methods in the optional "more infos" part
- descriptions are preceded by a space
- we use a custom convention, with @param, @return, @raise. Arguments types can be optionaly specified in the form (type1, type2), after the name (with one space to separate) and before the :. If a non builtin class is used, use it as it is imported (e.g.: exceptions.FeatureNotFound). Types like callable and iterable can be used
- in case of @return, D can be used before the type as a shortcut for Deferred, it is used before the type returned by the Deferred itself, as in the example. If you don't know the final type, (D) alone is acceptable.
- no blank line before the last """, which must be on its own line
- widely used parameters can use a unique description, they are then referenced with the syntax %(doc_param_name)s
- if you use a list (see arg3 in this example), use dashes (-) and align them like you would do for Python code (i.e. multiples of 4 spaces, at least 1 indentation level).
- for dictionary, (key: type, value: type) syntax is optional. In the enumerated items, if the line start with value:, then it describes the value, else it's one possible key. In case of nested dictionary (like in the example), new descriptions can be done (but think about using a known type to avoid too complex descriptions, ex. entity_data instead of dict).
Text command use docstring for self documentation, it's a special case
Here is an example:
def cmd_bookmark(self, mess_data, profile): """Bookmark a MUC room @command (group): [autojoin] - autojoin: join room automatically on connection """
- the command always starts with cmd_ prefix
- the first line of the docstring is used for /help command description
- @command is used to indicate syntaxe completion, the first line show completion with parameters and command type, the following lines are used for parameters descriptions.
- command type can be:
- "group": the command is only used in MUC rooms, it should not appear in other conversations
- "one2one": the command is only used in one2one conversations, it should not appear in MUC groups
- "all": the command can be used everywhere, that's the default
- command syntaxe is described as follow:
- [option]: optional argument (autojoin can be put or not above)
- | is used for exclusive options, e.g. above option could be written [autojoin | noautojoin]
- UPPERCASE reserved word can be used to specify expected argument:
- ROOM_NICK: nick of the occupant of a room
- JID: any Jabber ID
- ROOM_JID: JID of a room where user is
- ROSTER_JID: a jid present in our roster
- ROSTER_CONTACT: a jid or anything allowing to identity a contact present in our roster (can be it's name)
- ROSTER_GROUP: a group present in our roster
- lowercase words are argument which we can't guess (e.g.: /title command could have the "new_title" lowercase argument)
- (argument): mandatory argument, parenthesis can be ommited when there is only one argument possible (i.e. no | is used)
Please refer yourself to Howto_contribute/en.