Naming conventions in pySDC

📜 Those rules may not be enforced by the current implementation of pySDC. However, they should be enforced for any contribution.

Naming convention are mostly inspired from the PEP-8 guidelines, even if some of them may be different. Of course, strictly following those rules is not always the best solution, as Guido Von Rossum’s key insight states :

A Foolish Consistency is the Hobgoblin of Little Minds

The most important idea at the end is to find a optimal compromise between

  • readability : Can someone else easily read and understand my code ?

  • effectiveness : Does my code avoid kilometers-long lines to do simple things ?

Both aspects are interdependent to ease maintaining/development of any code and improve its attractiveness to potential users.

First definitions

Possible Naming formats :

  • all-lowercase : variablenamelikethis

  • snake_case : variable_name_like_this

  • PascalCase : VariableNameLikeThis

  • camelCase : variableNameLikeThis

  • all-uppercase with underscore : VARIABLE_NAME_LIKE_THIS

  • all-uppercase with minus : VARIABLE-NAME-LIKE-THIS

Packages and modules names

Modules should have short, all-lowercase names. Underscores can be used in the module name if it improves readability (i.e use snake_case only if it helps, else try to stick to all-lowercase). Python packages should also have short, all-lowercase names, although the use of underscores is discouraged.

Class names

Class names should use PascalCase formatting, for instance :

class AdvectionDiffusion(Problem):
    pass

The shorter, the better. Also, exception class names should end with the suffix Error, for instance

class ParameterError(Exception):
    pass

Function and variables names

Function (or method) and variable names should use camelCase formatting, and same goes for function arguments. For instance :

tLeft = 1
quadType = 'LEGENDRE'

def computeFejerRule(nNodes):
    # ...

class NodeGenerator():
    def getOrthogPolyCoeffs(self, nCoeffs):
        # ...

📜 A few additional notes :

  1. In general, shorter name (eventually with abbreviations) should be favored, as long as it does not deteriorate understandability. For instance getOrthogPolyCoeffs rather than getOrthogonalPolynomialCoefficients.

  2. Suffix s for plural should be used even with abbreviations for consistency (e.g nCoeffs, nNodes, …).

  3. Acronyms can be used to simplify variable names, but try not to start with it. For instance, favor jacobiMSSDC or multiStepSDCJacobi rather than MSSDCJacobi. In general, acronyms should be put at the end of variable names.

  4. Underscore can exceptionally be used at the end of variable names when it make readability better and ease further developments. In that case, the characters after the underscore should be all-uppercase with underscore (minus is not allowed by Python syntax). For instance when defining the same method with different specializations :

class MySweeper(Sweeper):

    def __init__(self, initSweep):
        try:
            self.initSweep = getattr(self, f'_initSweep_{initSweep}')
        except AttributeError:
            raise NotImplementedError(f'initSweep={initSweep}')

    def _initSweep_COPY(self):
        pass

    def _initSweep_SPREAD(self):
        pass

    # ... other implementations for initSweep

Private and public attributes

There is no such thing as private or public attributes in Python. But some attributes, if uses only within the object methods, can be indicated as private using the _ prefix. For instance :

class ChuckNorris():

    def __init__(self, param):
        self.param = param

    def _think(self):
        print('...')

    def act(self):
        if self.param == 'doubt':
            self._think()
        print('*?%&$?*§"$*$*§#{*')

📜 In general, variable name starting with double underscore __ are usually left for Python built-in names, e.g __dict__, __init__, …

Constants

Constants are usually defined on a module level and written in all-uppercase with underscores (all-uppercase with minus are not allowed by Python syntax). Examples :

NODE_TYPES = ['EQUID', 'LEGENDRE', 'CHEBY-1', 'CHEBY-2', 'CHEBY-3', 'CHEBY-4']
QUAD_TYPES = ['GAUSS', 'RADAU-LEFT', 'RADAU-RIGHT', 'LOBATTO']

For constant string values, however, favor the use of all uppercase with minus, e.g RADAU-RIGHT, LEGENDRE-NUMPY to distinguish those from constants names.

🔔 When constants are used, for instance, to select method specializations (with suffix using all-uppercase with underscore), it is probably better to keep all-uppercase with minus for constant string values and add a character replacement in between, for instance :

class MySweeper(Sweeper):

    def __init__(self, initSweep):
        try:
            self.initSweep = getattr(self, f'_initSweep_{initSweep.replace('-','_')}')
        except AttributeError:
            raise NotImplementedError(f'initSweep={initSweep}')

    def _initSweep_COPY_PASTE(self):
        pass

    def _initSweep_SPREAD_OUT(self):
        pass

    # ... other implementations for initSweep

⬅️ Back to Continuous Integration — ⬆️ Contributing Summary — ➡️ Next to Custom Implementations