{"id":25732451,"url":"https://github.com/vigo/textmate2-python-fmt","last_synced_at":"2025-05-07T19:03:06.492Z","repository":{"id":20884715,"uuid":"91183277","full_name":"vigo/textmate2-python-fmt","owner":"vigo","description":"Python FMT is a python linter/formatter/checker for TextMate.","archived":false,"fork":false,"pushed_at":"2024-05-14T17:23:55.000Z","size":27700,"stargazers_count":13,"open_issues_count":3,"forks_count":5,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-31T13:05:07.659Z","etag":null,"topics":["bundle","flake8","pep8","python","textmate"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vigo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":"Support/goto_error_line.rb","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"vigo","patreon":"vigoo"}},"created_at":"2017-05-13T15:19:43.000Z","updated_at":"2024-05-14T17:23:57.000Z","dependencies_parsed_at":"2025-02-26T03:41:18.997Z","dependency_job_id":"3f9add40-3cc1-4088-9659-9a455bff1091","html_url":"https://github.com/vigo/textmate2-python-fmt","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vigo%2Ftextmate2-python-fmt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vigo%2Ftextmate2-python-fmt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vigo%2Ftextmate2-python-fmt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vigo%2Ftextmate2-python-fmt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vigo","download_url":"https://codeload.github.com/vigo/textmate2-python-fmt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252940883,"owners_count":21828766,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bundle","flake8","pep8","python","textmate"],"created_at":"2025-02-26T03:41:08.884Z","updated_at":"2025-05-07T19:03:06.368Z","avatar_url":"https://github.com/vigo.png","language":"Ruby","funding_links":["https://github.com/sponsors/vigo","https://patreon.com/vigoo"],"categories":[],"sub_categories":[],"readme":"![Version](https://img.shields.io/badge/version-4.1.1-orange.svg)\n![Plaftorm](https://img.shields.io/badge/platform-TextMate-blue.svg)\n![Python 3.7+](https://img.shields.io/badge/python-3.7+-blue.svg)\n![macOS](https://img.shields.io/badge/macos-HighSierra-yellow.svg)\n![macOS](https://img.shields.io/badge/macos-Mojave-yellow.svg)\n![macOS](https://img.shields.io/badge/macos-Catalina-yellow.svg)\n![macOS](https://img.shields.io/badge/macos-BigSur-yellow.svg)\n![macOS](https://img.shields.io/badge/macos-Monterey-yellow.svg)\n![macOS](https://img.shields.io/badge/macos-Ventura-yellow.svg)\n![macOS](https://img.shields.io/badge/macos-Sonoma-yellow.svg)\n![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)\n[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat\u0026labelColor=ef8336)](https://pycqa.github.io/isort/)\n[![linting: pylint](https://img.shields.io/badge/linting-pylint-yellowgreen)](https://github.com/pylint-dev/pylint)\n[![style: flake8](https://img.shields.io/badge/style-flake8-blue)](https://github.com/PyCQA/flake8)\n![Powered by Rake](https://img.shields.io/badge/powered_by-rake-blue?logo=ruby)\n\n# Python FMT bundle for TextMate\n\n![Demo 1](Screenshots/demo-1.gif? \"Demo 1\")\n\nThis bundle runs various linters and checkers when you save a Python file,\nboth formatting the code and highlighting any errors. The supported linters\nand checkers are as follows:\n\n- `isort`: Sorts `import` statements.\n- `black`: Formats source code.\n- `pylint`: Analyses source code.\n- `flake8`: Checks source code for style guide enforcement.\n\n---\n\n## Installation\n\n`python` must be installed, whether through `brew`, `pyenv`, or any other\nmethod. Please check your python installation:\n\n```bash\ncommand -v python\n```\n\nBundle checks the `TM_PYTHON_FMT_PYTHON_PATH` environment variable. This\nvariable can be set in `.tm_properties` or via the \n**TextMate \u003e Preferences \u003e Variables** menu. If it is not set anywhere, the \nbundle attempts to locate the python path using the `command -v python` command \nand `TM_PYTHON_FMT_VIRTUAL_ENV` environment variable internally. If the bundle\nreports that it cannot find the `TM_PYTHON_FMT_PYTHON_PATH`, you need to set \nit manually to the desired python path.\n\nIf you are in a virtual environment, all you need is to set\n`TM_PYTHON_FMT_VIRTUAL_ENV` variable. Bundle will handle all the installed\nlinters/checkers from the virtual environment.\n\nIf you are not in a virtual environment, you need to set all the required\nvariables:\n\n- `TM_PYTHON_FMT_PYTHON_PATH`\n- `TM_PYTHON_FMT_BLACK`\n- `TM_PYTHON_FMT_ISORT`\n- `TM_PYTHON_FMT_PYLINT`\n- `TM_PYTHON_FMT_FLAKE8`\n\nif you want to use all of it. You can disable partially by setting\n`TM_PYTHON_FMT_DISABLE_\u003cNAME\u003e` environment variable(s).\n\nYou can set the values globally from command-line:\n\n```bash\n$ defaults write com.macromates.TextMate environmentVariables \\\n    -array-add \"{enabled = 1; value = \\\"$(command -v python)\\\"; name = \\\"TM_PYTHON_FMT_PYTHON_PATH\\\"; }\"\n```\n\nYou need to restart TextMate to take effect. Now clone the bundle:\n\n```bash\ncd \"${HOME}/Library/Application\\ Support/TextMate/Bundles/\"\ngit clone https://github.com/vigo/textmate2-python-fmt.git Python-FMT.tmbundle\n```\n\n\u003e **IMPORTANT**: Bundle ships with TextMate grammar: **Python FMT**. You\n**must** set your language scope to **Python FMT** for the bundle to\nfunction/work properly. Scope automatically loads `source.python` and \n`source.python.django` grammars. Due to TextMate’s callback flow, I was forced \nto create a separate scope. Otherwise, it would conflict with all bundles that \nuse `source.python`. Due to this situation, previous version was working too\nslow.\n\nIf you are within a project folder, the bundle automatically uses any existing\nlinter configuration files you have, such as `.isort`, `.flake8` and all the\nother configuration files.\n\nThe bundle includes a `requirements.txt` file, which allows for easy\ninstallation either into your virtual environment or system-wide:\n\n```bash\ncd Python-FMT.tmbundle/\n# if you need to create new environment uncomment below\n# mkvirtualenv myenv\npip install -r requirements.txt\n```\n\n`requirements.txt` contains:\n\n    black\n    isort\n    pylint\n    flake8\n    flake8-bandit\n    flake8-blind-except\n    flake8-bugbear\n    flake8-builtins\n    flake8-commas\n    flake8-print\n    flake8-quotes\n    flake8-return\n    flake8-string-format\n\nBundle contains easy config creation command; hit \n\u003ckbd\u003e⌥\u003c/kbd\u003e + \u003ckbd\u003eT\u003c/kbd\u003e (option + T) for helper commands.\n\n---\n\n![Demo 2](Screenshots/demo-2.gif? \"Demo 2\")\n\n## Enable / Disable Bundle or Features\n\nTo completely disable the bundle, simply assign a value to `TM_PYTHON_FMT_DISABLE`. \nThis allows you to proceed as if the bundle does not exist. Additionally, if \nthe first line of your Python file contains comment **TM\\_PYTHON\\_FMT_DISABLE**:\n\n```python\n# TM_PYTHON_FMT_DISABLE\nprint('ok')\n```\n \nthe bundle will also be disabled for that file. You can partially disable\nfeatures by setting related environment variable:\n\n- Set `TM_PYTHON_FMT_DISABLE_BLACK=1` to bypass `black` formatter\n- Set `TM_PYTHON_FMT_DISABLE_ISORT=1` to bypass `isort`\n- Set `TM_PYTHON_FMT_DISABLE_PYLINT=1` to disable `pylint` (well a bit useless :)\n- Set `TM_PYTHON_FMT_DISABLE_FLAKE8=1` to disable `flake8`\n\nThere is a helper snippet for disabling features easily, write `envi\u003cTAB\u003e`\nin `.tm_properties` file and select which feature to disable.\n\n---\n\n## TextMate Variables\n\n| Variable | Default Value | Description | \n|:---------|:-----|:-----|\n| `ENABLE_LOGGING` |  | Set for development purposes |\n| `TOOLTIP_LINE_LENGTH` | `100` | Width of pop-up window |\n| `TOOLTIP_LEFT_PADDING` | `2` | Alignment value |\n| `TOOLTIP_BORDER_CHAR` | `-` | Border value |\n| `TM_PYTHON_FMT_VIRTUAL_ENV` |  | Set this variable if you are in a virtual environment |\n| `TM_PYTHON_FMT_BLACK` | * | Binary path of `black` |\n| `TM_PYTHON_FMT_ISORT` | * | Binary path of `isort` |\n| `TM_PYTHON_FMT_PYLINT` | * | Binary path of `pylint` |\n| `TM_PYTHON_FMT_FLAKE8` | * | Binary path of `flake8` |\n| `TM_PYTHON_FMT_DISABLE` |  | Disable bundle |\n| `TM_PYTHON_FMT_DISABLE_BLACK` |  | Disable `black` formatter |\n| `TM_PYTHON_FMT_DISABLE_ISORT` |  | Disable `isort` |\n| `TM_PYTHON_FMT_DISABLE_PYLINT` |  | Disable `pylint` checker |\n| `TM_PYTHON_FMT_DISABLE_FLAKE8` |  | Disable `flake8` style guide |\n| `TM_PYTHON_FMT_BLACK_DEFAULTS` |  | Override current `black` config with extra parameters if provided |\n| `TM_PYTHON_FMT_ISORT_DEFAULTS` |  | Override current `isort` config with extra parameters if parameters |\n| `TM_PYTHON_FMT_PYLINT_EXTRA_OPTIONS` |  | Override current `pylint` config with extra parameters if parameters |\n| `TM_PYTHON_FMT_FLAKE8_DEFAULTS` |  | Override current `flake8` config with extra parameters if parameters |\n\n`*`: Bundle tries to find binary path, fall-back is empty/nil value, if you get\nerror, you need to set exact binary path.\n\nFor `black`, bundle checks config files in order below, last found overrides\nall!\n\n1. `${HOME}/.black`\n1. `${TM_PROJECT_DIRECTORY}/pyproject.toml`\n\nalso filenames end with `.pyi`\n\nFor `isort`, bundle checks config file order;\n\n1. `${HOME}/.isort.cfg`\n1. `${TM_PROJECT_DIRECTORY}/.isort.cfg`\n\nFor `pylint`, bundle checks config files below;\n\n1. `${HOME}/.pylintrc`\n1. `${TM_PROJECT_DIRECTORY}/.pylintrc`\n\nFor `flake8`, bundle checks config files below;\n\n1. `${HOME}/.flake8`\n1. `${TM_PROJECT_DIRECTORY}/.flake8`\n1. `${TM_PROJECT_DIRECTORY}/tox.ini`\n1. `${TM_PROJECT_DIRECTORY}/setup.cfg`\n\n`pylint` now shows every available error. You can set extra options to\ndisplay **compile-time errors** only by setting `TM_PYTHON_FMT_PYLINT_EXTRA_OPTIONS`\nvariable. Space delimited arguments are required:\n\n    # .tm_properties or from TextMate \u003e Preferences \u003e Variables\n    TM_PYTHON_FMT_PYLINT_EXTRA_OPTIONS=\"--errors-only\"\n\n`flake8` and `pylint` using same error output format:\n\n    LINE_NUMBER || COLUMN_NUMBER || ERROR_CODE || ERROR_MESSAGE\n\nExample `.tm_properties`:\n\n    TM_PYTHON_FMT_VIRTUAL_ENV=\"/Users/YOU/.virtualenvs/YOUR_VENV\"   # or\n    TM_PYTHON_FMT_VIRTUAL_ENV=\"${HOME}/.virtualenvs/YOUR_VENV\"\n    \n    # It’s ok to use shell variables and TextMate variables but never use like this:\n    # ~/.virtualenvs/ENV\n    \n    # overriders\n    TM_PYTHON_FMT_BLACK_DEFAULTS=\"--line-length=100\"\n    TM_PYTHON_FMT_ISORT_DEFAULTS=\"--line-length=40 --multi-line=GRID\"\n    TM_PYTHON_FMT_FLAKE8_DEFAULTS=\"--extend-ignore F401\"\n    TM_PYTHON_FMT_PYLINT_EXTRA_OPTIONS=\"--py3k\"\n\nAlso, you can set project based configurations for all of the tools. Check\ntheir official documentations:\n\n- https://black.readthedocs.io/en/stable/\n- https://pycqa.github.io/isort/\n- https://pylint.pycqa.org/en/latest/\n- https://flake8.pycqa.org/en/latest/\n\n---\n\n## Hot Keys and Snippets\n\n| Hot Keys and TAB Completions       | Description                                                                                                                                                                                           |\n|:-----------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| \u003ckbd\u003e⌥\u003c/kbd\u003e + \u003ckbd\u003eD\u003c/kbd\u003e       | Bypass black formating (toggle) for selection. |\n| \u003ckbd\u003e⌥\u003c/kbd\u003e + \u003ckbd\u003eT\u003c/kbd\u003e       | Create `.tm_properties` or linter config files |\n| \u003ckbd\u003e⌥\u003c/kbd\u003e + \u003ckbd\u003eG\u003c/kbd\u003e       | Go to error line! New feature! |\n| \u003ckbd\u003enoq\u003c/kbd\u003e + \u003ckbd\u003e⇥\u003c/kbd\u003e     | Choose desired bypass method |\n| \u003ckbd\u003eenvi\u003c/kbd\u003e + \u003ckbd\u003e⇥\u003c/kbd\u003e    | Inserts helpful environment variables if you are editing on `.tm_properties` file. Try :) |\n| \u003ckbd\u003edisable\u003c/kbd\u003e + \u003ckbd\u003e⇥\u003c/kbd\u003e | Inserts `# TM_PYTHON_FMT_DISABLE`, put this in to first line if you want to disable this bundle |\n\n---\n\n## Bug Report\n\nPlease set/enable the logger via setting `ENABLE_LOGGING=1`. Logs are written to\nthe `/tmp/textmate-python-fmt.log` file. You can `tail` while running via;\n`tail -f /tmp/textmate-python-fmt.log` in another Terminal tab. You can see\nlive what’s going on. Please provide the log information for bug reporting.\n\n`callback.document.will-save` errors are written to \n`/tmp/textmate-python-fmt-DOCUMENT-ID.error`.\n\nBundle log looks like this:\n\n    [2024-05-13 01:39:48][Python-FMT][INFO][python_fmt.rb-\u003erun_document_will_save]: will run isort\n    [2024-05-13 01:39:48][Python-FMT][DEBUG][linters.rb-\u003eisort]: cmd: \"/Users/vigo/.virtualenvs/thesarraf.com/bin/isort\" | version: 5.13.2 | args: [\"--profile\", \"black\", \"--honor-noqa\", \"--virtual-env\", \"/Users/vigo/.virtualenvs/thesarraf.com\", \"-\"]\n    [2024-05-13 01:39:48][Python-FMT][DEBUG][linters.rb-\u003eisort]: out:\n    \"FOO = 1\\n\"\n\n    err: \"\"\n    [2024-05-13 01:39:48][Python-FMT][INFO][python_fmt.rb-\u003efind_binary]: python -\u003e path: \"/Users/vigo/.virtualenvs/thesarraf.com/bin/python\"\n    [2024-05-13 01:39:48][Python-FMT][INFO][python_fmt.rb-\u003efind_binary]: black -\u003e path: \"/Users/vigo/.virtualenvs/thesarraf.com/bin/black\"\n    [2024-05-13 01:39:48][Python-FMT][INFO][python_fmt.rb-\u003efind_binary]: isort -\u003e path: \"/Users/vigo/.virtualenvs/thesarraf.com/bin/isort\"\n    [2024-05-13 01:39:48][Python-FMT][INFO][python_fmt.rb-\u003efind_binary]: pylint -\u003e path: \"/Users/vigo/.virtualenvs/thesarraf.com/bin/pylint\"\n    [2024-05-13 01:39:48][Python-FMT][INFO][python_fmt.rb-\u003efind_binary]: flake8 -\u003e path: \"/Users/vigo/.virtualenvs/thesarraf.com/bin/flake8\"\n    [2024-05-13 01:39:48][Python-FMT][INFO][python_fmt.rb-\u003ecan_run_run_document_did_save?]: any? true\n    [2024-05-13 01:39:48][Python-FMT][ERROR][python_fmt.rb-\u003ecan_run_run_document_did_save?]: warning_messages: []\n    [2024-05-13 01:39:49][Python-FMT][ERROR][python_fmt.rb-\u003erun_document_did_save]: errors_flake8: nil\n    [2024-05-13 01:39:49][Python-FMT][ERROR][python_fmt.rb-\u003erun_document_did_save]: all_errors: {}\n    [2024-05-13 01:39:49][Python-FMT][INFO][storage.rb-\u003edestroy]: storage.destroy for 1D082B22-3346-4DCE-BF76-FAE8BF4AE776 - (/tmp/textmate-python-fmt-1D082B22-3346-4DCE-BF76-FAE8BF4AE776.goto)\n    [2024-05-13 01:39:49][Python-FMT][INFO][storage.rb-\u003eadd]: storage.add for 1D082B22-3346-4DCE-BF76-FAE8BF4AE776 (/tmp/textmate-python-fmt-1D082B22-3346-4DCE-BF76-FAE8BF4AE776.goto)\n\n\nAfter you fix the source code (next run) bundle removes those files if there\nis no error. According to you bug report, you can `tail` or copy/paste the\ncontents of error file to issue.\n\nAlso, while running bundle script (which is TextMate’s default ruby 1.8.7),\nif error occurs, TextMate pops up an alert window. Please add that screen shot\nor try to copy error text from modal dialog.\n\n---\n\n## Change Log\n\n**2024-05-14**\n\n- Small improvements in project structure\n\n---\n\n**2024-05-13**\n\nAnother refactoring\n\n- Add go to line with `option+G`\n- Implement zero-config run, if you have linter, runs w/o config file, uses defaults\n- Improve error handling\n- Improve code structure\n- Add all the `noqa` codes for `pylint` and `flake8` for autocompletion.\n\nYou can read the whole story [here][changelog].\n\n---\n\n## Contributor(s)\n\n* [Uğur \"vigo\" Özyılmazel](https://github.com/vigo) - Creator, maintainer\n\n---\n\n## Contribute\n\nAll PR’s are welcome!\n\n1. `fork` (https://github.com/vigo/textmate2-python-fmt/fork)\n1. Create your `branch` (`git checkout -b my-features`)\n1. `commit` yours (`git commit -am 'add awesome features'`)\n1. `push` your `branch` (`git push origin my-features`)\n1. Than create a new **Pull Request**!\n\nThis project is intended to be a safe, welcoming space for collaboration, and\ncontributors are expected to adhere to the [code of conduct][coc].\n\n---\n\n## License\n\nThis project is licensed under MIT\n\n---\n\n[coc]: https://github.com/vigo/statoo/blob/main/CODE_OF_CONDUCT.md\n[changelog]: https://github.com/vigo/statoo/blob/main/CHANGELOG.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvigo%2Ftextmate2-python-fmt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvigo%2Ftextmate2-python-fmt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvigo%2Ftextmate2-python-fmt/lists"}