# Python

## Supported versions <a href="#supported-versions" id="supported-versions"></a>

* Python 3.x
* Python 2.x

## Language-specific properties <a href="#language-specific-properties" id="language-specific-properties"></a>

Discover and update the Python-specific [analysis-parameters](https://docs.sonarsource.com/sonarqube-server/9.9/analyzing-source-code/analysis-parameters "mention") in **Administration > General Settings > Languages > Python**.

## Handling project Python version <a href="#project-python-version" id="project-python-version"></a>

Python code is analyzed by default as compatible with python 2 and python 3. Some issues will be automatically silenced to avoid raising False Positives. In order to get a more precise analysis you can specify the Python versions your code supports via the `sonar.py.version` parameter.

The accepted format is a comma-separated list of versions having the format "X.Y"

Examples:

* `sonar.py.version=2.7`
* `sonar.py.version=3.8`
* `sonar.py.version=2.7, 3.7, 3.8, 3.9`

This parameter can be used in the *sonar-project.properties* file or the SonarScanner CLI command.

## Custom rules <a href="#custom-rules" id="custom-rules"></a>

## Overview <a href="#overview" id="overview"></a>

The Python analyzer parses the source code, creates an abstract syntax tree (AST), and then walks through the entire tree. A coding rule is a visitor that is able to visit nodes from this AST.

As soon as the coding rule visits a node, it can navigate its children and log issues if necessary.

### Writing a plugin <a href="#writing-a-plugin" id="writing-a-plugin"></a>

Custom rules for Python can be added by writing a SonarQube Plugin and using Python analyzer APIs. Here are the steps to follow:

**Create a SonarQube plugin**

* Create a standard SonarQube plugin project.
* Attach this plugin to the SonarQube Python analyzer through the `pom.xml`:
  * Add the dependency to the Python analyzer.
  * Add the following line in the sonar-packaging-maven-plugin configuration. `<requirePlugins>python:2.0-SNAPSHOT</requirePlugins>`
* Implement the following extension points:
  * [Plugin](https://javadocs.sonarsource.org/10.3.0.1951/org/sonar/api/Plugin.html)
  * [RulesDefinition](https://javadocs.sonarsource.org/10.3.0.1951/org/sonar/api/server/rule/RulesDefinition.html) and [PythonCustomRuleRepository](https://github.com/SonarSource/sonar-python/blob/c957e33/python-frontend/src/main/java/org/sonar/plugins/python/api/PythonCustomRuleRepository.java), which can be implemented by a single class, to declare your custom rules.
* Declare the RulesDefinition as an extension in the Plugin extension point.

**Implement a rule**

* Create a class that will hold the implementation of the rule, it should:
  * extend `PythonVisitorCheck` or `PythonSubscriptionCheck`.
  * Define the rule name, key, tags, etc. This can be done either by adding Java annotations or by adding them directly in the corresponding JSON file, like [this one](https://github.com/SonarSource/sonar-python/blob/master/docs/python-custom-rules-example/src/main/resources/org/sonar/l10n/python/rules/python/subscription.json).
* declare this class in the `RulesDefinition`.

### Example plugin <a href="#example-plugin" id="example-plugin"></a>

A sample plugin can be found here: [python-custom-rules-example](https://github.com/SonarSource/sonar-python/tree/master/docs/python-custom-rules-example) to help you get started.

### Implementation details <a href="#implementation-details" id="implementation-details"></a>

**Using PythonVisitorCheck**

To explore a part of the AST, override a method from `PythonVisitorCheck`. For example, if you want to explore "if statement" nodes, override the `visitIfStatement` method that will be called each time an [ifStatement](https://github.com/SonarSource/sonar-python/blob/c957e33/python-frontend/src/main/java/org/sonar/plugins/python/api/tree/IfStatement.java) node is encountered in the AST.

{% hint style="warning" %}
When overriding a visit method, you must call the super method in order to allow the visitor to visit the children of the node.
{% endhint %}

**Using PythonSubscriptionCheck**

To explore a part of the AST, override [`PythonSubscriptionCheck#initialize`](https://github.com/SonarSource/sonar-python/blob/c957e33/python-frontend/src/main/java/org/sonar/plugins/python/api/SubscriptionCheck.java#L26) and call [`SubscriptionCheck.Context#registerSyntaxNodeConsumer`](https://github.com/SonarSource/sonar-python/blob/c957e33/python-frontend/src/main/java/org/sonar/plugins/python/api/SubscriptionCheck.java#L30) with the [`Tree#Kind`](https://github.com/SonarSource/sonar-python/blob/c957e33/python-frontend/src/main/java/org/sonar/plugins/python/api/tree/Tree.java#L42) of node you want to visit. For example, if you want to explore "if statement", you should register to the kind [`Tree#Kind#IF_STATEMENT`](https://github.com/SonarSource/sonar-python/blob/c957e33/python-frontend/src/main/java/org/sonar/plugins/python/api/tree/Tree.java#L115) and then provide a lambda that will consume a [`SubscriptionContext`](https://github.com/SonarSource/sonar-python/blob/c957e33/python-frontend/src/main/java/org/sonar/plugins/python/api/SubscriptionContext.java#L33) to act on such nodes.

**Create issues**

From the check, an issue can be created by calling the [`SubscriptionContext#addIssue`](https://github.com/SonarSource/sonar-python/blob/c957e33/python-frontend/src/main/java/org/sonar/plugins/python/api/SubscriptionContext.java#L36) method or a `PythonVisitorCheck` [`#addIssue`](https://github.com/SonarSource/sonar-python/blob/c957e33/python-frontend/src/main/java/org/sonar/plugins/python/api/PythonVisitorCheck.java#L35) method.

**Testing checks**

You can use the [`PythonCheckVerifier#verify`](https://github.com/SonarSource/sonar-python/blob/c957e33/python-checks-testkit/src/main/java/org/sonar/python/checks/utils/PythonCheckVerifier.java) method to test custom checks. Don’t forget to add the testkit dependency to access this class from your project:

```css-79elbk
  <dependency>
      <groupId>org.sonarsource.python</groupId>
      <artifactId>python-checks-testkit</artifactId>
      <version>${project.version}</version>
      <scope>test</scope>
  </dependency>
```

You should end each line having an issue with a comment in the following form:

```css-79elbk
# Noncompliant {{Message}}
```

Comment syntax is described [here](https://github.com/SonarSource/sonar-analyzer-commons/blob/38db754/test-commons/README.md).

## Related Pages <a href="#related-pages" id="related-pages"></a>

* [importing-third-party-issues](https://docs.sonarsource.com/sonarqube-server/9.9/analyzing-source-code/importing-external-issues/importing-third-party-issues "mention") ([Pylint](https://pylint.pycqa.org/), [Bandit](https://github.com/PyCQA/bandit/blob/master/README.rst), [Flake8](https://flake8.pycqa.org/en/latest/))
* [overview](https://docs.sonarsource.com/sonarqube-server/9.9/analyzing-source-code/test-coverage/overview "mention") (the [Coverage tool](http://nedbatchelder.com/code/coverage/) provided by [Ned Batchelder](http://nedbatchelder.com/), [Nose](https://nose.readthedocs.org/en/latest/), [pytest](https://docs.pytest.org/en/latest/))
