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 ]
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() }
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.")
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")
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".'
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}"
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", ]
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", } )
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
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"])
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"] )
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
"""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.