For every star on GitHub, we'll donate $2 to clean up our waterways. Star us now!
Meltano uses the below tools to enforce consistent code style. Explore the repo to learn of the specific rules and settings of each.
Python:
Flake8 is a python tool that glues together pycodestyle
, pyflakes
, mccabe
, and third-party plugins to check the style and quality of python code. Notable among these is wemake-python-styleguide
, which offers an extensive set of opinionated rules that encourage clean and correct code.
To lint your Python code, install the project using poetry install
, then run poetry run pre-commit --all-files flakeheaven
from the root of the project. The pre-commit
check will be run in CI on all PRs.
Javascript:
To lint your Javascript code, run yarn lint
from the root of the project.
MyPy is being adopted incrementally by this codebase. If you are adding new code, please use type hints.
If you are making changes to existing Python modules, you are encouraged to enable type checks. To do so,
if you are fixing a single .py
file inside a sub-package, e.g. meltano.core.plugin.command
, de-glob the sub-package in pyproject.toml
and enumerate the files you are not touching. This will allow you to run nox -rs mypy
and catch type errors only in the files you are touching.
[[tool.mypy.overrides]]
module = [
...
"meltano.core.m5o.*",
- "meltano.core.plugin.*",
+ "meltano.core.plugin.airflow",
+ "meltano.core.plugin.base",
+ # Note that meltano.core.plugin.command is not included here
+ "meltano.core.plugin.config_service",
+ "meltano.core.plugin.dbt.*",
+ "meltano.core.plugin.error",
+ "meltano.core.plugin.factory",
+ "meltano.core.plugin.file",
+ "meltano.core.plugin.meltano_file",
+ "meltano.core.plugin.model.*",
+ "meltano.core.plugin.project_plugin",
+ "meltano.core.plugin.requirements",
+ "meltano.core.plugin.settings_service",
+ "meltano.core.plugin.singer.*",
+ "meltano.core.plugin.superset",
+ "meltano.core.plugin.utility",
"meltano.core.runner.*",
...
]
if you are fixing an entire sub-package, simply remove it from the ignore list.
A contributor should know the exact line-of-code to make a change based on convention
In the spirit of GitLab’s “boring solutions” with the above tools and mantra, the codebase is additionally sorted as follows:
Javascript import
s are sorted using the following pattern:
Tip: There should be only 2 blocks of imports with a single blank line between both blocks. The first rule is used to separate both blocks.
import lodash from 'lodash' // 1: third-party, 2: default, 3: [l]odash
import Vue from 'vue' // 1: third-party, 2: default, 3: [v]ue
import { bar, foo } from 'alib' // 1: third-party, 2: partial, 3: [a]lib
import { mapAction, mapState } from 'vuex' // 1: third-party, 2: partial, 3: [v]uex
¶ // 1 blank line to split import groups
import Widget from '@/component/Widget' // 1: local, 2: default, 3: @/[c]omponent/Widget
import poller from '@/utils/poller' // 1: local, 2: default, 3: @/[u]tils/poller
import { Medal } from '@/component/globals' // 1: local, 2: partial, 3: @/[c]omponent/globals
import { bar, thing } from '@/utils/utils' // 1: local, 2: partial, 3: @/[u]tils/utils
¶
¶ // 2 blank lines to split the imports from the code
Python imports are sorted automatically using isort
. This is executed as part of the make lint
command, as well as during execution of the pre-commit hook.
Object properties and methods are alphabetical where Vuex
stores are the exception (defaultState
-> getters
-> actions
-> mutations
)
When testing your contributions you may need to ensure that your various `__pycache__` directories are removed. This helps ensure that you are running the code you expect to be running.
Sometimes it is useful to be able to make preview features available or allow deprecated features to be used for backwards compatibility.
To accomplish this, Meltano implements feature flags.
For new, deprecated, or experimental features, the relevant code path can be wrapped in a feature flag context. The process for adding new feature flags is as follows:
FeatureFlags
Enum valueProjectSettingsService.feature_flag()
context as demonstrated below.This feature is experimental and must be enabled using feature flags. See the docs here: …
# Example feature flag usage
from meltano.core.project import Project
from meltano.core.project_settings_service import ProjectSettingsService
from meltano.core.settings_service import FeatureFlags
class ExistingClass:
def __init__(self):
self.project = Project.find()
self.settings_service = ProjectSettingsService(self.project)
# If this method is called elsewhere in the code and the NEW_BEHAVIOR
# feature flag is not set to 'true' it will throw an error:
def experimental_method(self):
with self.settings_service.feature_flag(FeatureFlags.NEW_BEHAVIOR):
print("Doing new behavior...")
# If this method is called elsewhere, its behavior will vary based on whether
# the feature flag is set in the project
# The same pattern can be used to deprecate existing behavior
# Notice the "raise_error=False" in the feature_flag method call
def existing_method_with_new_behavior(self):
with self.settings_service.feature_flag(FeatureFlags.NEW_BEHAVIOR, raise_error=False) as new_behavior:
if new_behavior:
print("Doing the new behavior...")
else:
print("Doing the existing behavior...")