{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "===============\n",
    "Getting Started\n",
    "===============\n",
    "Use ``pip install fixit`` to install Fixit.\n",
    "\n",
    "Analyze Code Issues and Autofix Issues\n",
    "======================================\n",
    "\n",
    "Given an example code (``example.py``) like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "nbsphinx": "hidden"
   },
   "outputs": [],
   "source": [
    "import tempfile\n",
    "temp_dir = tempfile.TemporaryDirectory()\n",
    "import os\n",
    "os.chdir(\"../../\")\n",
    "cwd = ! pwd\n",
    "cwd = cwd[0]\n",
    "os.chdir(temp_dir.name)\n",
    "pyre_config = f\"{cwd}/.pyre_configuration\"\n",
    "watchman_config = f\"{cwd}/.watchmanconfig\"\n",
    "! cp $pyre_config $temp_dir.name\n",
    "! cp $watchman_config $temp_dir.name\n",
    "%env PYTHONPATH=$cwd\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')\n",
    "print(temp_dir.name)\n",
    "from pathlib import Path\n",
    "file_path = str(Path(temp_dir.name) / \"example.py\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%writefile $file_path\n",
    "from typing import Dict\n",
    "\n",
    "\n",
    "class C(object):\n",
    "    attr = \"ab\" \"cd\" \"ef\" \"gh\"\n",
    "\n",
    "    def method(self) -> Dict[int, str]:\n",
    "        filtered_char = []\n",
    "        for char in self.attr:\n",
    "            if char is not \"a\":\n",
    "                filtered_char.append(char)\n",
    "\n",
    "        index_to_char = dict([(idx, char) for idx, char in enumerate(filtered_char)])\n",
    "        return index_to_char"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "nbsphinx": "hidden"
   },
   "outputs": [],
   "source": [
    "! pyre start --store-type-check-resolution\n",
    "! git init\n",
    "! git add example.py\n",
    "! pyre query \"types(path='example.py')\""
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "We can run Fixit rules to check code issues:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! python -m fixit.cli.run_rules"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "Each warning shows the violation's position in the format of ``file_name:starting_line_number:starting_column_number``, follwed by the lint rule name and lint message.\n",
    "\n",
    "To fix the issues automatically:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! python -m fixit.cli.apply_fix"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "All the issues are automatically fixed!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! git diff"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "Configuration File\n",
    "==================\n",
    "A Fixit configuration file allows you to configure Fixit settings for your codebase.\n",
    "\n",
    "1. To initialize a configuration file populated with some defaults, run::\n",
    "\n",
    "    python -m fixit.cli.init_config\n",
    "\n",
    "  This will create a ``.fixit.config.yaml`` with default settings in the current working directory.\n",
    "\n",
    "2. Next, you may wish to edit or add some specific settings. The available configurations are:\n",
    "\n",
    "- ``allow_list_rules``: A list of rules (whether custom of from Fixit) that should be applied to the repository. Omitting this setting allows all rules to run. For example:\n",
    "\n",
    "    allow_list_rules: [Flake8PseudoLintRule]\n",
    "    \n",
    "``block_list_rules`` takes precendence, so if a rule is in both ``allow_list_rules`` and ``block_list_rules`` the rule will not be run. \n",
    "\n",
    "- ``block_list_patterns``: A list of patterns that indicate that a file should not be linted. For example::\n",
    "\n",
    "    block_list_patterns: ['@generated', '@nolint']\n",
    "\n",
    "  will tell Fixit to skip linting any files that have ``@generated`` or ``@nolint`` in their contents.\n",
    "\n",
    "- ``block_list_rules``: A list of rules (whether custom or from Fixit) that should not be applied to the repository. For example::\n",
    "\n",
    "    block_list_rules: [NoInheritFromObjectRule]\n",
    "\n",
    "- ``fixture_dir``: The directory in which fixture files required for unit testing are to be found. This is only necessary if you are testing rules that use a metadata cache (see :ref:`AwaitAsyncCallRule` for an example of such a rule). This can be an absolute path, or a path relative to `repo_root` (see below).\n",
    "- ``use_noqa``: Defaults to ``False``.  Use ``True`` to support Flake8 lint suppression comment: noqa. The noqa is not recommended because a bare noqa implicitly silences all lint errors which prevent other useful lint errors to show up. We recommend use ``lint-fixme`` or ``lint-ignore`` suppression comments.\n",
    "- ``formatter``: A list of the formatter commands to use after a lint is complete. These will be passed to the ``args`` parameter in `subprocess.check_output <https://docs.python.org/3.8/library/subprocess.html#subprocess.check_output>`_ in the order in which they appear. For example::\n",
    "\n",
    "    formatter: [black, '-']\n",
    "\n",
    "  Here, the formatter of choice would be `Black <https://black.readthedocs.io/en/stable/>`_ and the added ``-`` tells it to read from standard input, and write to standard output so that it is compatible with Fixit's formatting logic.\n",
    "\n",
    "- ``packages``: The Python packages in which to search for lint rules. For example::\n",
    "\n",
    "    packages: [fixit.rules, my.custom.package]\n",
    "\n",
    "- ``repo_root``: The path to the repository root. This can be a path relative to the `.fixit.config.yaml` file or an absolute path. For example::\n",
    "\n",
    "    repo_root: .\n",
    "\n",
    "- ``rule_config``: Rule-specific configurations. For example::\n",
    "\n",
    "    ImportConstraintsRule:\n",
    "        fixit:\n",
    "            rules: [[\"*\", \"allow\"]]\n",
    "\n",
    "  (see :ref:`ImportConstraintsRule` for more details on this example)\n",
    "\n",
    "3. A `.fixit.config.yaml` example with populated settings::\n",
    "\n",
    "    block_list_patterns:\n",
    "    - '@generated'\n",
    "    - '@nolint'\n",
    "    block_list_rules:\n",
    "    - BlockListedRule\n",
    "    fixture_dir: ./tests/fixtures\n",
    "    formatter:\n",
    "    - black\n",
    "    - '-'\n",
    "    packages:\n",
    "    - fixit.rules\n",
    "    repo_root: .\n",
    "    rule_config:\n",
    "        ImportConstraintsRule:\n",
    "            fixit:\n",
    "                rules: [[\"*\", \"allow\"]]\n",
    "\n",
    "\n",
    "Enforcing Custom Rules\n",
    "======================\n",
    "\n",
    "After finishing up the configuration, you may wish to enforce some custom lint rules in your repository.\n",
    "\n",
    "1. Start by creating a directory where your custom rules will live. Make sure to include an ``__init__.py`` file so that the directory is importable as a package.\n",
    "This can simply be an empty file. For example::\n",
    "\n",
    "    my_repo_root\n",
    "        └── lint\n",
    "            └── custom_rules\n",
    "                └── __init__.py\n",
    "\n",
    "2. Include the dotted name of the package in the `.fixit.config.yaml` file under the `packages` setting::\n",
    "\n",
    "    packages:\n",
    "    - fixit.rules\n",
    "    - lint.custom_rules\n",
    "\n",
    "3. See the :doc:`Build a Lint Rule <build_a_lint_rule>` page for more details on how to write the logic for a custom lint rule.\n",
    "\n",
    "\n",
    "Running Lint Rules\n",
    "==================\n",
    "\n",
    "You may also want to run some rules against your repository to see all current violations.\n",
    "\n",
    "- To run only the pre-packaged Fixit rules against the entire repository, run::\n",
    "\n",
    "    python -m fixit.cli.run_rules --rules fixit.rules\n",
    "\n",
    "- To run only your custom rules package against the entire repository, run::\n",
    "\n",
    "    python -m fixit.cli.run_rules --rules <dotted_name_of_custom_package>\n",
    "\n",
    "- To run a specific rule against the entire repository, run::\n",
    "\n",
    "    python -m fixit.cli.run_rules --rules <rule_name>\n",
    "\n",
    "- To run all the rule packages under the ``packages`` settings in the `.fixit.config.yaml` file against the entire repository, run::\n",
    "\n",
    "    python -m fixit.cli.run_rules\n",
    "\n",
    "- To run all the rule packages under the ``packages`` settings in the `.fixit.config.yaml` file against a particular file or directory, run::\n",
    "\n",
    "    python -m fixit.cli.run_rules <file_or_directory>\n",
    "\n",
    "- To run all the rule packages under the ``packages`` settings in the `.fixit.config.yaml` file against mutliple files or directories, run::\n",
    "\n",
    "    python -m fixit.cli.run_rules <file_or_directory> <file_or_directory2> <file_or_directory3>\n",
    "\n",
    "\n",
    "Applying Autofixes\n",
    "==================\n",
    "\n",
    "Some rules come with provided autofix suggestions. We have provided a script to help you automatically apply these suggested fixes. To do this, run::\n",
    "\n",
    "    python -m fixit.cli.apply_fix <file_or_directory> --rules <rule_name_or_package>\n",
    "\n",
    "This will apply one or more lint rules' autofix to the source code in the specified file(s) or directory.\n",
    "\n",
    "- For more detailes on this script's usage, run::\n",
    "\n",
    "    python -m fixit.cli.apply_fix --help\n",
    "\n",
    "\n",
    "Suppressing Violations\n",
    "======================\n",
    "\n",
    "You may wish to suppress existing lint violations from the lint engine altogether. We have provided a script to help you automatically insert lint suppressions. To do this, run::\n",
    "\n",
    "    python -m fixit.cli.insert_suppressions <rule_name> <file_or_directory>\n",
    "\n",
    "This will insert a suppression in the form of a ``# lint-fixme`` comment above lines in the source code that violate the specified rule.\n",
    "\n",
    "- For more detailes on this script's usage, run::\n",
    "\n",
    "    python -m fixit.cli.insert_suppressions --help"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "nbsphinx": "hidden"
   },
   "outputs": [],
   "source": [
    "temp_dir.cleanup()"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Raw Cell Format",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
