diff --git a/.arclint b/.arclint
--- a/.arclint
+++ b/.arclint
@@ -292,6 +292,12 @@
             "type": "prettier",
             "include": "(^web/.*\\.(css|html|js|json|jsx|md|scss|ts|tsx)$)",
             "exclude": "(^web/.*/translations/.*\\.json$)"
+        },
+        "lint-python-isort": {
+            "type": "lint-python-isort",
+            "version": ">=5.0.0",
+            "include": "(\\.py$)",
+            "exclude": "(^contrib/)"
         }
     }
 }
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -133,7 +133,7 @@
 
 On Ubuntu 20.04:
 ```
-sudo apt-get install clang-format clang-tidy clang-tools cppcheck python3-autopep8 flake8 php-codesniffer yamllint
+sudo apt-get install clang-format clang-tidy clang-tools cppcheck python3-isort python3-autopep8 flake8 php-codesniffer yamllint
 ```
 
 If not available in the distribution, `clang-format-10` and `clang-tidy` can be
diff --git a/arcanist/.phutil_module_cache b/arcanist/.phutil_module_cache
--- a/arcanist/.phutil_module_cache
+++ b/arcanist/.phutil_module_cache
@@ -1 +1 @@
-{"__symbol_cache_version__":11,"2f99c841a569f2029d13ea030dee007c":{"have":{"class":{"TestsLinter":103}},"need":{"function":{"pht":318,"id":2638},"class":{"ArcanistExternalLinter":123,"ArcanistLintMessage":2645,"Filesystem":776,"ArcanistLinter":2693,"ArcanistLintSeverity":2801}},"xmap":{"TestsLinter":["ArcanistExternalLinter"]}},"2809b09d2021203b43c57da33d1fe8bf":{"have":{"class":{"AssertWithSideEffectsLinter":210}},"need":{"function":{"pht":439},"class":{"ArcanistLinter":246,"ArcanistLintSeverity":926,"Filesystem":1170}},"xmap":{"AssertWithSideEffectsLinter":["ArcanistLinter"]}},"38f0c676bff5192a344464142caaa253":{"have":{"class":{"CHeaderLinter":99}},"need":{"function":{"pht":611},"class":{"ArcanistLinter":121,"ArcanistLintSeverity":1060,"Filesystem":1307}},"xmap":{"CHeaderLinter":["ArcanistLinter"]}},"fbb3938ab9b412d7505335d9f7ed183d":{"have":{"class":{"ShellCheckLinter":95}},"need":{"function":{"pht":921,"execx":1443,"id":2414},"class":{"ArcanistExternalLinter":120,"ArcanistLintMessage":2421,"ArcanistLintSeverity":646,"ArcanistLinter":2469}},"xmap":{"ShellCheckLinter":["ArcanistExternalLinter"]}},"39694cf756ce58681ea84a028f3e007f":{"have":{"class":{"IncludeGuardLinter":98}},"need":{"function":{"pht":443},"class":{"ArcanistLinter":125,"ArcanistLintSeverity":796,"Filesystem":1162}},"xmap":{"IncludeGuardLinter":["ArcanistLinter"]}},"cfe5966affc66e3444c34bf55a119446":{"have":{"function":{"startsWith":16},"class":{"MarkdownLinter":171}},"need":{"function":{"pht":361},"class":{"ArcanistLinter":194,"ArcanistLintSeverity":652,"Filesystem":1571}},"xmap":{"MarkdownLinter":["ArcanistLinter"]}},"63d19a8745cb2e1200cc26488dc7ad25":{"have":{"class":{"CheckRpcMappingsLinter":131}},"need":{"function":{"pht":310,"id":1386},"class":{"GlobalExternalLinter":162,"ArcanistLintMessage":1393,"Filesystem":573,"ArcanistLinter":1443,"ArcanistLintSeverity":1544}},"xmap":{"CheckRpcMappingsLinter":["GlobalExternalLinter"]}},"09b7af4806790af70a69ee97158e6112":{"have":{"class":{"CheckNonFatalOverAssertInRpc":268}},"need":{"function":{"pht":582},"class":{"ArcanistLinter":305,"ArcanistLintSeverity":863,"Filesystem":1144}},"xmap":{"CheckNonFatalOverAssertInRpc":["ArcanistLinter"]}},"85936cbfc0decd1aae05001717b359da":{"have":{"class":{"LogLinter":116}},"need":{"function":{"pht":297},"class":{"ArcanistLinter":134,"ArcanistLintSeverity":580,"Filesystem":875}},"xmap":{"LogLinter":["ArcanistLinter"]}},"9285ad9415f8ebe564f7119e5a72c559":{"have":{"class":{"FormatStringLinter":146}},"need":{"function":{"pht":377,"csprintf":1492,"id":1872},"class":{"ArcanistExternalLinter":173,"ArcanistLintMessage":1879,"Filesystem":827,"ArcanistLinter":1956,"ArcanistLintSeverity":2044}},"xmap":{"FormatStringLinter":["ArcanistExternalLinter"]}},"ab6085aa9abe6394d7f8ceffe6554c50":{"have":{"class":{"WhitespaceLinter":59}},"need":{"function":{"pht":258},"class":{"ArcanistLinter":84,"ArcanistLintSeverity":545,"Filesystem":948}},"xmap":{"WhitespaceLinter":["ArcanistLinter"]}},"e4678dca551a849892aff414d3c4e24e":{"have":{"class":{"DoxygenLinter":91}},"need":{"function":{"pht":382},"class":{"ArcanistLinter":113,"ArcanistLintSeverity":695,"Filesystem":943}},"xmap":{"DoxygenLinter":["ArcanistLinter"]}},"2e11dd9ad67e594f863bc46ac59ea37e":{"have":{"class":{"GlobalExternalLinter":199}},"need":{"class":{"ArcanistExternalLinter":228},"interface":{"ILintOnce":262}},"xmap":{"GlobalExternalLinter":["ArcanistExternalLinter","ILintOnce"]}},"e6c7c36001803d09d667e83285bd04e7":{"have":{"class":{"YamllintLinter":77}},"need":{"function":{"pht":399,"execx":907,"id":1711},"class":{"ArcanistExternalLinter":100,"ArcanistLintMessage":1718,"ArcanistLintSeverity":184,"ArcanistLinter":1766}},"xmap":{"YamllintLinter":["ArcanistExternalLinter"]}},"5ea58c19df0397ed8ee0f463d90d6c72":{"have":{"class":{"BoostDependenciesLinter":145}},"need":{"function":{"pht":330,"id":1440},"class":{"GlobalExternalLinter":177,"ArcanistLintMessage":1447,"Filesystem":609,"ArcanistLinter":1524,"ArcanistLintSeverity":1624}},"xmap":{"BoostDependenciesLinter":["GlobalExternalLinter"]}},"3cd6909c95569e2564deabbd1ec38bbb":{"have":{"class":{"FileNameLinter":103}},"need":{"function":{"pht":382},"class":{"ArcanistLinter":126,"ArcanistLintSeverity":737,"Filesystem":1160}},"xmap":{"FileNameLinter":["ArcanistLinter"]}},"2cbb6e7228d81557f777ad648704f343":{"have":{"class":{"IncludeQuotesLinter":100}},"need":{"function":{"pht":306},"class":{"ArcanistLinter":128,"ArcanistLintSeverity":663,"Filesystem":964}},"xmap":{"IncludeQuotesLinter":["ArcanistLinter"]}},"90a8b110dc475955f15bb81d37268cb5":{"have":{"class":{"AutoPEP8FormatLinter":75}},"need":{"function":{"pht":297,"execx":769,"id":1903},"class":{"ArcanistExternalLinter":104,"ArcanistLintMessage":1910,"Filesystem":1754,"ArcanistLinter":2017,"ArcanistLintSeverity":2095}},"xmap":{"AutoPEP8FormatLinter":["ArcanistExternalLinter"]}},"454160ed72e88797129d84ee589de304":{"have":{"class":{"PythonShebangLinter":87}},"need":{"function":{"pht":290},"class":{"ArcanistLinter":115,"ArcanistLintSeverity":614,"Filesystem":854}},"xmap":{"PythonShebangLinter":["ArcanistLinter"]}},"729e2f379c278258d8040e156ba9da29":{"have":{"class":{"ShellLocaleLinter":107}},"need":{"function":{"pht":382},"class":{"ArcanistLinter":133,"ArcanistLintSeverity":734,"Filesystem":1044}},"xmap":{"ShellLocaleLinter":["ArcanistLinter"]}},"b2403124ec3e8be6cb4d10bf0f6c4134":{"have":{"interface":{"ILintOnce":69}},"need":[],"xmap":[]},"4c4adcac26dddfa5e350b85a40097755":{"have":{"class":{"BashShebangLinter":82}},"need":{"function":{"pht":281},"class":{"ArcanistLinter":108,"ArcanistLintSeverity":597,"Filesystem":837}},"xmap":{"BashShebangLinter":["ArcanistLinter"]}},"f151089cf79fdb8257b2272ed4782d88":{"have":{"class":{"IncludeSourceLinter":99}},"need":{"function":{"pht":391},"class":{"ArcanistLinter":127,"ArcanistLintSeverity":699,"Filesystem":938}},"xmap":{"IncludeSourceLinter":["ArcanistLinter"]}},"6f2f22dd0f259fb2eaa284b4fab3bc29":{"have":{"class":{"PythonFormatLinter":123}},"need":{"function":{"pht":353,"id":1838},"class":{"ArcanistExternalLinter":150,"ArcanistLintMessage":1845,"Filesystem":776,"ArcanistLinter":1970,"ArcanistLintSeverity":2053}},"xmap":{"PythonFormatLinter":["ArcanistExternalLinter"]}},"9bb48ec0fe2e9ced8e27d42540d0571c":{"have":{"class":{"CheckDocLinter":106}},"need":{"function":{"pht":321,"id":1845},"class":{"GlobalExternalLinter":129,"ArcanistLintMessage":1852,"Filesystem":729,"ArcanistLinter":1900,"ArcanistLintSeverity":1986}},"xmap":{"CheckDocLinter":["GlobalExternalLinter"]}},"146347e1ef63e514a6634ada8de5b5c9":{"have":{"class":{"Qt5Linter":70}},"need":{"function":{"pht":258},"class":{"ArcanistLinter":88,"ArcanistLintSeverity":609,"Filesystem":836}},"xmap":{"Qt5Linter":["ArcanistLinter"]}},"d792b114a2a4d16e2137dd237483ce42":{"have":{"class":{"PythonMutableDefaultLinter":155}},"need":{"function":{"pht":377},"class":{"ArcanistLinter":190,"ArcanistLintSeverity":740,"Filesystem":1030}},"xmap":{"PythonMutableDefaultLinter":["ArcanistLinter"]}},"b4005bc083930dd85220bffb4c5f8bdd":{"have":{"class":{"PythonFileEncodingLinter":111}},"need":{"function":{"pht":321},"class":{"ArcanistLinter":144,"ArcanistLintSeverity":685,"Filesystem":990}},"xmap":{"PythonFileEncodingLinter":["ArcanistLinter"]}},"e6886ead74de6310f1cbc0d589d8f5b0":{"have":{"class":{"ArcanistLandBotWorkflow":91}},"need":{"function":{"phutil_console_format":265,"pht":1577,"execx":2181},"class":{"ArcanistWorkflow":123,"ArcanistUsageException":2251}},"xmap":{"ArcanistLandBotWorkflow":["ArcanistWorkflow"]}},"ae5b7d3d6b8cf9598ce4abaf0cd56b21":{"have":{"class":{"ExtendedConfigurationDrivenLintEngine":19}},"need":{"function":{"newv":159,"pht":933},"class":{"ArcanistLintEngine":65,"ArcanistConfigurationDrivenLintEngine":171,"PhutilConsole":866},"class\/interface":{"ILintOnce":634}},"xmap":{"ExtendedConfigurationDrivenLintEngine":["ArcanistLintEngine"]}},"9780c82e3cf1cde0c46662563f00444f":{"have":{"class":{"ArcanistBitcoinABCConfiguration":13}},"need":{"function":{"pht":242},"class":{"ArcanistConfiguration":53,"ArcanistLintWorkflow":1652},"class\/interface":{"ArcanistWorkflow":385,"ArcanistNoEffectException":1371}},"xmap":{"ArcanistBitcoinABCConfiguration":["ArcanistConfiguration"]}},"df78f1ac61b2f0f7cd5bd3cf434ce6e3":{"have":{"class":{"CppVoidParameterLinter":119}},"need":{"function":{"pht":392},"class":{"ArcanistLinter":150,"ArcanistLintSeverity":707,"Filesystem":1164}},"xmap":{"CppVoidParameterLinter":["ArcanistLinter"]}},"1dacb6d661b7ea83e6b1980c3c4f602d":{"have":{"class":{"StdintLinter":90}},"need":{"function":{"pht":567},"class":{"ArcanistLinter":111,"ArcanistLintSeverity":876,"Filesystem":1401}},"xmap":{"StdintLinter":["ArcanistLinter"]}},"04d01863b9bf57f467af4808b397e584":{"have":{"class":{"MyPyLinter":88}},"need":{"function":{"pht":243,"execx":758,"id":1303},"class":{"ArcanistExternalLinter":107,"ArcanistLintMessage":1310,"ArcanistLinter":1358,"ArcanistLintSeverity":1464}},"xmap":{"MyPyLinter":["ArcanistExternalLinter"]}},"5b9143afa84a8b098359597987dcddfe":{"have":{"class":{"CppCheckLinter":92}},"need":{"function":{"pht":7401,"execx":7761},"class":{"ArcanistExternalLinter":115,"ArcanistLintMessage":10229,"Filesystem":9351,"ArcanistLintSeverity":10538}},"xmap":{"CppCheckLinter":["ArcanistExternalLinter"]}},"3a184a47bce0d3fbf7dad76c6f755df5":{"have":{"class":{"PrettierLinter":76}},"need":{"function":{"pht":311,"execx":758,"id":1196},"class":{"ArcanistExternalLinter":99,"ArcanistLintMessage":1203,"Filesystem":1118,"ArcanistLinter":1276,"ArcanistLintSeverity":1362}},"xmap":{"PrettierLinter":["ArcanistExternalLinter"]}},"4584b1b007576d47eeff9504b80c4a77":{"have":{"class":{"ClangFormatLinter":79}},"need":{"function":{"pht":302,"execx":781,"id":2251},"class":{"ArcanistExternalLinter":105,"ArcanistLintMessage":2258,"Filesystem":2102,"ArcanistLinter":2365,"ArcanistLintSeverity":2443}},"xmap":{"ClangFormatLinter":["ArcanistExternalLinter"]}},"2d7a2dd0f00ea1f93ee4488b2498cf08":{"have":{"class":{"LocaleDependenceLinter":160}},"need":{"function":{"pht":5621},"class":{"ArcanistLinter":191,"ArcanistLintSeverity":6124,"Filesystem":6370}},"xmap":{"LocaleDependenceLinter":["ArcanistLinter"]}}}
\ No newline at end of file
+{"__symbol_cache_version__":11,"df78f1ac61b2f0f7cd5bd3cf434ce6e3":{"have":{"class":{"CppVoidParameterLinter":119}},"need":{"function":{"pht":392},"class":{"ArcanistLinter":150,"ArcanistLintSeverity":707,"Filesystem":1164}},"xmap":{"CppVoidParameterLinter":["ArcanistLinter"]}},"2f99c841a569f2029d13ea030dee007c":{"have":{"class":{"TestsLinter":103}},"need":{"function":{"pht":318,"id":2638},"class":{"ArcanistExternalLinter":123,"ArcanistLintMessage":2645,"Filesystem":776,"ArcanistLinter":2693,"ArcanistLintSeverity":2801}},"xmap":{"TestsLinter":["ArcanistExternalLinter"]}},"2809b09d2021203b43c57da33d1fe8bf":{"have":{"class":{"AssertWithSideEffectsLinter":210}},"need":{"function":{"pht":439},"class":{"ArcanistLinter":246,"ArcanistLintSeverity":926,"Filesystem":1170}},"xmap":{"AssertWithSideEffectsLinter":["ArcanistLinter"]}},"38f0c676bff5192a344464142caaa253":{"have":{"class":{"CHeaderLinter":99}},"need":{"function":{"pht":611},"class":{"ArcanistLinter":121,"ArcanistLintSeverity":1060,"Filesystem":1307}},"xmap":{"CHeaderLinter":["ArcanistLinter"]}},"fbb3938ab9b412d7505335d9f7ed183d":{"have":{"class":{"ShellCheckLinter":95}},"need":{"function":{"pht":921,"execx":1443,"id":2414},"class":{"ArcanistExternalLinter":120,"ArcanistLintMessage":2421,"ArcanistLintSeverity":646,"ArcanistLinter":2469}},"xmap":{"ShellCheckLinter":["ArcanistExternalLinter"]}},"1dacb6d661b7ea83e6b1980c3c4f602d":{"have":{"class":{"StdintLinter":90}},"need":{"function":{"pht":567},"class":{"ArcanistLinter":111,"ArcanistLintSeverity":876,"Filesystem":1401}},"xmap":{"StdintLinter":["ArcanistLinter"]}},"39694cf756ce58681ea84a028f3e007f":{"have":{"class":{"IncludeGuardLinter":98}},"need":{"function":{"pht":443},"class":{"ArcanistLinter":125,"ArcanistLintSeverity":796,"Filesystem":1162}},"xmap":{"IncludeGuardLinter":["ArcanistLinter"]}},"cfe5966affc66e3444c34bf55a119446":{"have":{"function":{"startsWith":16},"class":{"MarkdownLinter":171}},"need":{"function":{"pht":361},"class":{"ArcanistLinter":194,"ArcanistLintSeverity":652,"Filesystem":1571}},"xmap":{"MarkdownLinter":["ArcanistLinter"]}},"63d19a8745cb2e1200cc26488dc7ad25":{"have":{"class":{"CheckRpcMappingsLinter":131}},"need":{"function":{"pht":310,"id":1386},"class":{"GlobalExternalLinter":162,"ArcanistLintMessage":1393,"Filesystem":573,"ArcanistLinter":1443,"ArcanistLintSeverity":1544}},"xmap":{"CheckRpcMappingsLinter":["GlobalExternalLinter"]}},"09b7af4806790af70a69ee97158e6112":{"have":{"class":{"CheckNonFatalOverAssertInRpc":268}},"need":{"function":{"pht":582},"class":{"ArcanistLinter":305,"ArcanistLintSeverity":863,"Filesystem":1144}},"xmap":{"CheckNonFatalOverAssertInRpc":["ArcanistLinter"]}},"85936cbfc0decd1aae05001717b359da":{"have":{"class":{"LogLinter":116}},"need":{"function":{"pht":297},"class":{"ArcanistLinter":134,"ArcanistLintSeverity":580,"Filesystem":875}},"xmap":{"LogLinter":["ArcanistLinter"]}},"9285ad9415f8ebe564f7119e5a72c559":{"have":{"class":{"FormatStringLinter":146}},"need":{"function":{"pht":377,"csprintf":1492,"id":1872},"class":{"ArcanistExternalLinter":173,"ArcanistLintMessage":1879,"Filesystem":827,"ArcanistLinter":1956,"ArcanistLintSeverity":2044}},"xmap":{"FormatStringLinter":["ArcanistExternalLinter"]}},"ab6085aa9abe6394d7f8ceffe6554c50":{"have":{"class":{"WhitespaceLinter":59}},"need":{"function":{"pht":258},"class":{"ArcanistLinter":84,"ArcanistLintSeverity":545,"Filesystem":948}},"xmap":{"WhitespaceLinter":["ArcanistLinter"]}},"e4678dca551a849892aff414d3c4e24e":{"have":{"class":{"DoxygenLinter":91}},"need":{"function":{"pht":382},"class":{"ArcanistLinter":113,"ArcanistLintSeverity":695,"Filesystem":943}},"xmap":{"DoxygenLinter":["ArcanistLinter"]}},"2e11dd9ad67e594f863bc46ac59ea37e":{"have":{"class":{"GlobalExternalLinter":199}},"need":{"class":{"ArcanistExternalLinter":228},"interface":{"ILintOnce":262}},"xmap":{"GlobalExternalLinter":["ArcanistExternalLinter","ILintOnce"]}},"e6c7c36001803d09d667e83285bd04e7":{"have":{"class":{"YamllintLinter":77}},"need":{"function":{"pht":399,"execx":907,"id":1711},"class":{"ArcanistExternalLinter":100,"ArcanistLintMessage":1718,"ArcanistLintSeverity":184,"ArcanistLinter":1766}},"xmap":{"YamllintLinter":["ArcanistExternalLinter"]}},"5ea58c19df0397ed8ee0f463d90d6c72":{"have":{"class":{"BoostDependenciesLinter":145}},"need":{"function":{"pht":330,"id":1440},"class":{"GlobalExternalLinter":177,"ArcanistLintMessage":1447,"Filesystem":609,"ArcanistLinter":1524,"ArcanistLintSeverity":1624}},"xmap":{"BoostDependenciesLinter":["GlobalExternalLinter"]}},"04d01863b9bf57f467af4808b397e584":{"have":{"class":{"MyPyLinter":88}},"need":{"function":{"pht":243,"execx":758,"id":1303},"class":{"ArcanistExternalLinter":107,"ArcanistLintMessage":1310,"ArcanistLinter":1358,"ArcanistLintSeverity":1464}},"xmap":{"MyPyLinter":["ArcanistExternalLinter"]}},"3cd6909c95569e2564deabbd1ec38bbb":{"have":{"class":{"FileNameLinter":103}},"need":{"function":{"pht":382},"class":{"ArcanistLinter":126,"ArcanistLintSeverity":737,"Filesystem":1160}},"xmap":{"FileNameLinter":["ArcanistLinter"]}},"5b9143afa84a8b098359597987dcddfe":{"have":{"class":{"CppCheckLinter":92}},"need":{"function":{"pht":7401,"execx":7761},"class":{"ArcanistExternalLinter":115,"ArcanistLintMessage":10229,"Filesystem":9351,"ArcanistLintSeverity":10538}},"xmap":{"CppCheckLinter":["ArcanistExternalLinter"]}},"2cbb6e7228d81557f777ad648704f343":{"have":{"class":{"IncludeQuotesLinter":100}},"need":{"function":{"pht":306},"class":{"ArcanistLinter":128,"ArcanistLintSeverity":663,"Filesystem":964}},"xmap":{"IncludeQuotesLinter":["ArcanistLinter"]}},"90a8b110dc475955f15bb81d37268cb5":{"have":{"class":{"AutoPEP8FormatLinter":75}},"need":{"function":{"pht":297,"execx":769,"id":1903},"class":{"ArcanistExternalLinter":104,"ArcanistLintMessage":1910,"Filesystem":1754,"ArcanistLinter":2017,"ArcanistLintSeverity":2095}},"xmap":{"AutoPEP8FormatLinter":["ArcanistExternalLinter"]}},"454160ed72e88797129d84ee589de304":{"have":{"class":{"PythonShebangLinter":87}},"need":{"function":{"pht":290},"class":{"ArcanistLinter":115,"ArcanistLintSeverity":614,"Filesystem":854}},"xmap":{"PythonShebangLinter":["ArcanistLinter"]}},"729e2f379c278258d8040e156ba9da29":{"have":{"class":{"ShellLocaleLinter":107}},"need":{"function":{"pht":382},"class":{"ArcanistLinter":133,"ArcanistLintSeverity":734,"Filesystem":1044}},"xmap":{"ShellLocaleLinter":["ArcanistLinter"]}},"b2403124ec3e8be6cb4d10bf0f6c4134":{"have":{"interface":{"ILintOnce":69}},"need":[],"xmap":[]},"4c4adcac26dddfa5e350b85a40097755":{"have":{"class":{"BashShebangLinter":82}},"need":{"function":{"pht":281},"class":{"ArcanistLinter":108,"ArcanistLintSeverity":597,"Filesystem":837}},"xmap":{"BashShebangLinter":["ArcanistLinter"]}},"f151089cf79fdb8257b2272ed4782d88":{"have":{"class":{"IncludeSourceLinter":99}},"need":{"function":{"pht":391},"class":{"ArcanistLinter":127,"ArcanistLintSeverity":699,"Filesystem":938}},"xmap":{"IncludeSourceLinter":["ArcanistLinter"]}},"6f2f22dd0f259fb2eaa284b4fab3bc29":{"have":{"class":{"PythonFormatLinter":123}},"need":{"function":{"pht":353,"id":1838},"class":{"ArcanistExternalLinter":150,"ArcanistLintMessage":1845,"Filesystem":776,"ArcanistLinter":1970,"ArcanistLintSeverity":2053}},"xmap":{"PythonFormatLinter":["ArcanistExternalLinter"]}},"3a184a47bce0d3fbf7dad76c6f755df5":{"have":{"class":{"PrettierLinter":76}},"need":{"function":{"pht":311,"execx":758,"id":1196},"class":{"ArcanistExternalLinter":99,"ArcanistLintMessage":1203,"Filesystem":1118,"ArcanistLinter":1276,"ArcanistLintSeverity":1362}},"xmap":{"PrettierLinter":["ArcanistExternalLinter"]}},"4584b1b007576d47eeff9504b80c4a77":{"have":{"class":{"ClangFormatLinter":79}},"need":{"function":{"pht":302,"execx":781,"id":2251},"class":{"ArcanistExternalLinter":105,"ArcanistLintMessage":2258,"Filesystem":2102,"ArcanistLinter":2365,"ArcanistLintSeverity":2443}},"xmap":{"ClangFormatLinter":["ArcanistExternalLinter"]}},"9bb48ec0fe2e9ced8e27d42540d0571c":{"have":{"class":{"CheckDocLinter":106}},"need":{"function":{"pht":321,"id":1845},"class":{"GlobalExternalLinter":129,"ArcanistLintMessage":1852,"Filesystem":729,"ArcanistLinter":1900,"ArcanistLintSeverity":1986}},"xmap":{"CheckDocLinter":["GlobalExternalLinter"]}},"146347e1ef63e514a6634ada8de5b5c9":{"have":{"class":{"Qt5Linter":70}},"need":{"function":{"pht":258},"class":{"ArcanistLinter":88,"ArcanistLintSeverity":609,"Filesystem":836}},"xmap":{"Qt5Linter":["ArcanistLinter"]}},"d792b114a2a4d16e2137dd237483ce42":{"have":{"class":{"PythonMutableDefaultLinter":155}},"need":{"function":{"pht":377},"class":{"ArcanistLinter":190,"ArcanistLintSeverity":740,"Filesystem":1030}},"xmap":{"PythonMutableDefaultLinter":["ArcanistLinter"]}},"b4005bc083930dd85220bffb4c5f8bdd":{"have":{"class":{"PythonFileEncodingLinter":111}},"need":{"function":{"pht":321},"class":{"ArcanistLinter":144,"ArcanistLintSeverity":685,"Filesystem":990}},"xmap":{"PythonFileEncodingLinter":["ArcanistLinter"]}},"e6886ead74de6310f1cbc0d589d8f5b0":{"have":{"class":{"ArcanistLandBotWorkflow":91}},"need":{"function":{"phutil_console_format":265,"pht":1577,"execx":2181},"class":{"ArcanistWorkflow":123,"ArcanistUsageException":2251}},"xmap":{"ArcanistLandBotWorkflow":["ArcanistWorkflow"]}},"ae5b7d3d6b8cf9598ce4abaf0cd56b21":{"have":{"class":{"ExtendedConfigurationDrivenLintEngine":19}},"need":{"function":{"newv":159,"pht":933},"class":{"ArcanistLintEngine":65,"ArcanistConfigurationDrivenLintEngine":171,"PhutilConsole":866},"class\/interface":{"ILintOnce":634}},"xmap":{"ExtendedConfigurationDrivenLintEngine":["ArcanistLintEngine"]}},"9780c82e3cf1cde0c46662563f00444f":{"have":{"class":{"ArcanistBitcoinABCConfiguration":13}},"need":{"function":{"pht":242},"class":{"ArcanistConfiguration":53,"ArcanistLintWorkflow":1652},"class\/interface":{"ArcanistWorkflow":385,"ArcanistNoEffectException":1371}},"xmap":{"ArcanistBitcoinABCConfiguration":["ArcanistConfiguration"]}},"c073131f5baad372e3037328d2e71c0e":{"have":{"class":{"ISortFormatLinter":72}},"need":{"function":{"pht":318,"id":1597},"class":{"ArcanistExternalLinter":98,"ArcanistLintMessage":1604,"Filesystem":1448,"ArcanistLinter":1711,"ArcanistLintSeverity":1790}},"xmap":{"ISortFormatLinter":["ArcanistExternalLinter"]}},"3e6f662aafff47b2f59242e1823e3b14":{"have":{"class":{"LocaleDependenceLinter":1741}},"need":{"function":{"pht":7202},"class":{"ArcanistLinter":1772,"ArcanistLintSeverity":7705,"Filesystem":7951}},"xmap":{"LocaleDependenceLinter":["ArcanistLinter"]}}}
\ No newline at end of file
diff --git a/arcanist/__phutil_library_map__.php b/arcanist/__phutil_library_map__.php
--- a/arcanist/__phutil_library_map__.php
+++ b/arcanist/__phutil_library_map__.php
@@ -28,6 +28,7 @@
     'FormatStringLinter' => 'linter/FormatStringLinter.php',
     'GlobalExternalLinter' => 'linter/GlobalExternalLinter.php',
     'ILintOnce' => 'linter/ILintOnce.php',
+    'ISortFormatLinter' => 'linter/ISortLinter.php',
     'IncludeGuardLinter' => 'linter/IncludeGuardLinter.php',
     'IncludeQuotesLinter' => 'linter/IncludeQuotesLinter.php',
     'IncludeSourceLinter' => 'linter/IncludeSourceLinter.php',
@@ -73,6 +74,7 @@
       'ArcanistExternalLinter',
       'ILintOnce',
     ),
+    'ISortFormatLinter' => 'ArcanistExternalLinter',
     'IncludeGuardLinter' => 'ArcanistLinter',
     'IncludeQuotesLinter' => 'ArcanistLinter',
     'IncludeSourceLinter' => 'ArcanistLinter',
diff --git a/arcanist/linter/ISortLinter.php b/arcanist/linter/ISortLinter.php
new file mode 100644
--- /dev/null
+++ b/arcanist/linter/ISortLinter.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * Isort your imports, so you don't have to.
+ */
+final class ISortFormatLinter extends ArcanistExternalLinter {
+
+  public function getInfoName() {
+    return 'isort';
+  }
+
+  public function getInfoURI() {
+    return 'https://pycqa.github.io/isort/';
+  }
+
+  public function getInfoDescription() {
+    return pht('Sort your python imports');
+  }
+
+  public function getLinterName() {
+    return 'isort';
+  }
+
+  public function getLinterConfigurationName() {
+    return 'lint-python-isort';
+  }
+
+  public function getDefaultBinary() {
+    return 'isort';
+  }
+
+  protected function getMandatoryFlags() {
+    return array(
+      /* Print to stdout instead of modifying in-place */
+      '--stdout',
+      /**
+       * Compatibility with black: one import per line with trailing commas,
+       * use parentheses, ensure newline before comments.
+       * See https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#isort
+       */
+      '--profile=black',
+      /* Use stricter rule than black, 79 instead of 88. */
+      '--line-length=79',
+    );
+  }
+
+  public function getInstallInstructions() {
+    return pht('Install isort with `pip install isort`');
+  }
+
+  public function shouldExpectCommandErrors() {
+    return false;
+  }
+
+  protected function parseLinterOutput($path, $err, $stdout, $stderr) {
+    $ok = ($err == 0);
+
+    if (!$ok) {
+      return false;
+    }
+
+    $root = $this->getProjectRoot();
+    $path = Filesystem::resolvePath($path, $root);
+    $orig = file_get_contents($path);
+    if ($orig == $stdout) {
+      return array();
+    }
+
+    $message = id(new ArcanistLintMessage())
+      ->setPath($path)
+      ->setLine(1)
+      ->setChar(1)
+      ->setGranularity(ArcanistLinter::GRANULARITY_FILE)
+      ->setCode('ISORT')
+      ->setSeverity(ArcanistLintSeverity::SEVERITY_AUTOFIX)
+      ->setName('Sorting Python imports')
+      ->setDescription("'$path' has unsorted imports.")
+      ->setOriginalText($orig)
+      ->setReplacementText($stdout);
+
+    return array($message);
+  }
+}