Example #1
0
def test__plugin_example_rules_returned():
    """Test that the example rules from the plugin are returned."""
    plugin_manager = get_plugin_manager()
    # The plugin import order is non-deterministic
    assert "Rule_Example_L001" in [
        rule.__name__ for rules in plugin_manager.hook.get_rules() for rule in rules
    ]
Example #2
0
def get_config_info() -> dict:
    """Gets the config from core sqlfluff and sqlfluff plugins and merges them."""
    plugin_manager = get_plugin_manager()
    configs_info = plugin_manager.hook.get_configs_info()
    return {
        k: v for config_info_dict in configs_info for k, v in config_info_dict.items()
    }
Example #3
0
def test_config_decorator():
    """Test rules with config_keywords have the @document_configuration decorator."""
    for plugin_rules in get_plugin_manager().hook.get_rules():
        for rule in plugin_rules:
            if hasattr(rule, "config_keywords"):
                assert is_configurable(rule), (
                    f"Rule {rule.__name__} has config but is not decorated with "
                    "@document_configuration to display that config.")
Example #4
0
def test_content_count(content, min_count):
    """Test docstring have specific content."""
    for plugin_rules in get_plugin_manager().hook.get_rules():
        for rule in plugin_rules:
            if rule._check_docstring is True:
                assert rule.__doc__.count(content) >= min_count, (
                    f"{rule.__name__} content {content} does not occur at least "
                    f"{min_count} times")
Example #5
0
def test_groups_decorator():
    """Test rules with groups have the @document_groups decorator."""
    for plugin_rules in get_plugin_manager().hook.get_rules():
        for rule in plugin_rules:
            if hasattr(rule, "groups"):
                assert is_documenting_groups(
                    rule
                ), f'Rule {rule.__name__} does not specify "@document_groups".'
Example #6
0
def test_keyword_anti_before_best():
    """Test docstring anti pattern before best pattern."""
    for plugin_rules in get_plugin_manager().hook.get_rules():
        for rule in plugin_rules:
            if rule._check_docstring is True:
                assert rule.__doc__.index(KEYWORD_ANTI) < rule.__doc__.index(
                    KEYWORD_BEST
                ), f"{rule.__name__} keyword {KEYWORD_BEST} appears before {KEYWORD_ANTI}"
Example #7
0
def test__plugin_manager_registers_example_plugin():
    """Test that the example plugin is registered."""
    plugin_manager = get_plugin_manager()
    # The plugin import order is non-deterministic
    assert sorted([
        plugin_module.__name__
        for plugin_module in plugin_manager.get_plugins()
    ]) == [
        "example.rules",
        "sqlfluff.core.plugin.lib",
    ]
Example #8
0
def test__plugin_manager_registers_example_plugin():
    """Test that the example plugin is registered."""
    plugin_manager = get_plugin_manager()
    # The plugin import order is non-deterministic.
    # Use sets in case the dbt plugin (or other plugins) are
    # already installed too.
    assert set(
        plugin_module.__name__ for plugin_module in plugin_manager.get_plugins()
    ).issuperset(
        {
            "example.rules",
            "sqlfluff.core.plugin.lib",
        }
    )
Example #9
0
def _load_standard_rules():
    """Initialise the standard ruleset.

    We do this on each call so that dynamic rules changes
    are possible.
    """
    std_rule_set = RuleSet(name="standard",
                           config_info=STANDARD_CONFIG_INFO_DICT)

    # Iterate through the rules list and register each rule with the standard set.
    for plugin_rules in get_plugin_manager().hook.get_rules():
        for rule in plugin_rules:
            std_rule_set.register(rule)

    return std_rule_set
Example #10
0
    def __init__(self,
                 configs: Optional[dict] = None,
                 overrides: Optional[dict] = None):
        self._overrides = overrides  # We only store this for child configs
        defaults = nested_combine(
            *get_plugin_manager().hook.load_default_config())
        self._configs = nested_combine(defaults, configs or {"core": {}},
                                       {"core": overrides or {}})
        # Some configs require special treatment
        self._configs["core"]["color"] = (False if self._configs["core"].get(
            "nocolor", False) else None)
        # Deal with potential ignore parameters
        if self._configs["core"].get("ignore", None):
            self._configs["core"][
                "ignore"] = self._split_comma_separated_string(
                    self._configs["core"]["ignore"])
        else:
            self._configs["core"]["ignore"] = []
        # Whitelists and blacklists
        if self._configs["core"].get("rules", None):
            self._configs["core"][
                "rule_whitelist"] = self._split_comma_separated_string(
                    self._configs["core"]["rules"])
        else:
            self._configs["core"]["rule_whitelist"] = None
        if self._configs["core"].get("exclude_rules", None):
            self._configs["core"][
                "rule_blacklist"] = self._split_comma_separated_string(
                    self._configs["core"]["exclude_rules"])
        else:
            self._configs["core"]["rule_blacklist"] = None
        # Configure Recursion
        if self._configs["core"].get("recurse", 0) == 0:
            self._configs["core"]["recurse"] = True

        # Dialect and Template selection.
        # NB: We import here to avoid a circular references.
        from sqlfluff.core.dialects import dialect_selector
        from sqlfluff.core.templaters import templater_selector

        self._configs["core"]["dialect_obj"] = dialect_selector(
            self._configs["core"]["dialect"])
        self._configs["core"]["templater_obj"] = templater_selector(
            self._configs["core"]["templater"])
Example #11
0
    def __init__(
        self,
        configs: Optional[dict] = None,
        extra_config_path: Optional[str] = None,
        ignore_local_config: bool = False,
        overrides: Optional[dict] = None,
        plugin_manager: Optional[pluggy.PluginManager] = None,
        # Ideally a dialect should be set when config is read but sometimes
        # it might only be set in nested .sqlfluff config files, so allow it
        # to be not required.
        require_dialect: bool = True,
    ):
        self._extra_config_path = (
            extra_config_path  # We only store this for child configs
        )
        self._ignore_local_config = (
            ignore_local_config  # We only store this for child configs
        )
        self._overrides = overrides  # We only store this for child configs

        # Fetch a fresh plugin manager if we weren't provided with one
        self._plugin_manager = plugin_manager or get_plugin_manager()

        defaults = nested_combine(*self._plugin_manager.hook.load_default_config())
        self._configs = nested_combine(
            defaults, configs or {"core": {}}, {"core": overrides or {}}
        )
        # Some configs require special treatment
        self._configs["core"]["color"] = (
            False if self._configs["core"].get("nocolor", False) else None
        )
        # Deal with potential ignore parameters
        if self._configs["core"].get("ignore", None):
            self._configs["core"]["ignore"] = _split_comma_separated_string(
                self._configs["core"]["ignore"]
            )
        else:
            self._configs["core"]["ignore"] = []
        # Allowlists and denylists
        if self._configs["core"].get("rules", None):
            self._configs["core"]["rule_allowlist"] = _split_comma_separated_string(
                self._configs["core"]["rules"]
            )
        else:
            self._configs["core"]["rule_allowlist"] = None
        if self._configs["core"].get("exclude_rules", None):
            self._configs["core"]["rule_denylist"] = _split_comma_separated_string(
                self._configs["core"]["exclude_rules"]
            )
        else:
            self._configs["core"]["rule_denylist"] = None
        # Configure Recursion
        if self._configs["core"].get("recurse", 0) == 0:
            self._configs["core"]["recurse"] = True

        # Dialect and Template selection.
        # NB: We import here to avoid a circular references.
        from sqlfluff.core.dialects import dialect_selector

        dialect: Optional[str] = self._configs["core"]["dialect"]
        if dialect is not None:
            self._configs["core"]["dialect_obj"] = dialect_selector(
                self._configs["core"]["dialect"]
            )
        elif require_dialect:
            self.verify_dialect_specified()
        self._configs["core"]["templater_obj"] = self.get_templater(
            self._configs["core"]["templater"]
        )
Example #12
0
def core_options(f: Callable) -> Callable:
    """Add core operation options to commands via a decorator.

    These are applied to the main (but not all) cli commands like
    `parse`, `lint` and `fix`.
    """
    # Only enable dialect completion if on version of click
    # that supports it
    if shell_completion_enabled:
        f = click.option(
            "-d",
            "--dialect",
            default=None,
            help="The dialect of SQL to lint",
            shell_complete=dialect_shell_complete,
        )(f)
    else:  # pragma: no cover
        f = click.option(
            "-d",
            "--dialect",
            default=None,
            help="The dialect of SQL to lint",
        )(f)
    f = click.option(
        "-t",
        "--templater",
        default=None,
        help="The templater to use (default=jinja)",
        type=click.Choice(
            [
                templater.name
                for templater in chain.from_iterable(
                    get_plugin_manager().hook.get_templaters()
                )
            ]
        ),
    )(f)
    f = click.option(
        "-r",
        "--rules",
        default=None,
        help=(
            "Narrow the search to only specific rules. For example "
            "specifying `--rules L001` will only search for rule `L001` (Unnecessary "
            "trailing whitespace). Multiple rules can be specified with commas e.g. "
            "`--rules L001,L002` will specify only looking for violations of rule "
            "`L001` and rule `L002`."
        ),
    )(f)
    f = click.option(
        "-e",
        "--exclude-rules",
        default=None,
        help=(
            "Exclude specific rules. For example "
            "specifying `--exclude-rules L001` will remove rule `L001` (Unnecessary "
            "trailing whitespace) from the set of considered rules. This could either "
            "be the allowlist, or the general set if there is no specific allowlist. "
            "Multiple rules can be specified with commas e.g. "
            "`--exclude-rules L001,L002` will exclude violations of rule "
            "`L001` and rule `L002`."
        ),
    )(f)
    f = click.option(
        "--config",
        "extra_config_path",
        default=None,
        help=(
            "Include additional config file. By default the config is generated "
            "from the standard configuration files described in the documentation. "
            "This argument allows you to specify an additional configuration file that "
            "overrides the standard configuration files. N.B. cfg format is required."
        ),
        type=click.Path(),
    )(f)
    f = click.option(
        "--ignore-local-config",
        is_flag=True,
        help=(
            "Ignore config files in default search path locations. "
            "This option allows the user to lint with the default config "
            "or can be used in conjunction with --config to only "
            "reference the custom config file."
        ),
    )(f)
    f = click.option(
        "--encoding",
        default=None,
        help=(
            "Specify encoding to use when reading and writing files. Defaults to "
            "autodetect."
        ),
    )(f)
    f = click.option(
        "-i",
        "--ignore",
        default=None,
        help=(
            "Ignore particular families of errors so that they don't cause a failed "
            "run. For example `--ignore parsing` would mean that any parsing errors "
            "are ignored and don't influence the success or fail of a run. "
            "`--ignore` behaves somewhat like `noqa` comments, except it "
            "applies globally. Multiple options are possible if comma separated: "
            "e.g. `--ignore parsing,templating`."
        ),
    )(f)
    f = click.option(
        "--bench",
        is_flag=True,
        help="Set this flag to engage the benchmarking tool output.",
    )(f)
    f = click.option(
        "--logger",
        type=click.Choice(
            ["templater", "lexer", "parser", "linter", "rules"], case_sensitive=False
        ),
        help="Choose to limit the logging to one of the loggers.",
    )(f)
    f = click.option(
        "--disable-noqa",
        is_flag=True,
        default=None,
        help="Set this flag to ignore inline noqa comments.",
    )(f)
    return f
Example #13
0
"""Register all the rule classes with their corresponding rulesets (just std currently)."""

from sqlfluff.core.rules.base import RuleSet
from sqlfluff.core.rules.config_info import STANDARD_CONFIG_INFO_DICT
from sqlfluff.core.plugin.host import get_plugin_manager

std_rule_set = RuleSet(name="standard", config_info=STANDARD_CONFIG_INFO_DICT)

# Sphinx effectively runs an import * from this module in rules.rst, so initialise
# __all__ with an empty list before we populate it with the rule names.
__all__ = []

# Iterate through the rules list and register each rule with the std_rule_set
for plugin_rules in get_plugin_manager().hook.get_rules():
    for rule in plugin_rules:
        std_rule_set.register(rule)

        # Add the Rule classes to the module namespace with globals() so that they can
        # be found by Sphinx automodule documentation in rules.rst
        # The result is the same as declaring the classes in this file.
        # Rules coming from the "Example" plugin are excluded from the
        # documentation.
        globals()[rule.__name__] = rule
        # Add the rule class names to __all__ for Sphinx automodule discovery
        __all__.append(rule.__name__)


def get_ruleset(name: str = "standard") -> RuleSet:
    """Get a ruleset by name."""
    lookup = {std_rule_set.name: std_rule_set}
    # Return a copy in case someone modifies the register.