├── .gitignore ├── .jshintrc ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── img ├── config.gif ├── example.gif └── install.gif ├── lib ├── cache.js ├── cache.js.map ├── config.js ├── config.js.map ├── init.js ├── init.js.map ├── linter.js ├── linter.js.map ├── logger.js ├── logger.js.map ├── parser.js ├── parser.js.map ├── runner.js ├── runner.js.map ├── util.js └── util.js.map ├── package.json ├── src ├── cache.ts ├── config.ts ├── init.ts ├── linter.ts ├── logger.ts ├── parser.ts ├── runner.ts └── util.ts ├── test.py ├── tsconfig.json └── typings.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | typings 5 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esnext": true, 3 | "moz": true 4 | } 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | #### 3.1.2 2 | * (#37) Fix issue: Cannot read property 'getPath' of undefined 3 | 4 | #### 3.1.1 5 | * Update release notes and readme file 6 | 7 | #### 3.1.0 8 | * (#31) Execution finished with error because of pylama exit code change 9 | 10 | #### 3.0.5 11 | * (#28) Add cache functionality 12 | * (#25) Remove underline options from plugin configuration 13 | * (#27) Documentation update 14 | * (#26) Regenerate new plugin exaples 15 | 16 | #### 3.0.4 17 | * Rewrite whole plugin to typescript 18 | * (#23) Remove logic responsible by disabling console 19 | * (#22) Add link to lint errors 20 | * (#17) Change "Lint trigger" option names 21 | * Fix few deployment issues 22 | * Add colorLink option 23 | 24 | #### 2.1.7 25 | * Fix error if file is in edition without project 26 | 27 | #### 2.1.6 28 | * Add option to run only single lint instance 29 | * Fix error with blocked lint operation 30 | * Change way how results are returned to linter 31 | 32 | #### 2.1.5 33 | * Fix error with lint plugins order 34 | * Fix error related to messages without error code 35 | 36 | #### 2.1.4 37 | * Reduce plugin dependencies 38 | * Reduce plugin startup 39 | 40 | #### 2.1.3 41 | * Fix error message 42 | * Set whole line for errors with position 0 43 | * Set items order in settings window 44 | * Speed up startup 45 | 46 | #### 2.1.2 47 | * Update package documentation 48 | 49 | #### 2.1.1 50 | * Update package description 51 | 52 | #### 2.1.0 53 | * Move documentation to separate project 54 | * Add trigger options: after save, after change, after save and change 55 | * Add option to define underscore type and size 56 | 57 | #### 2.0.0 58 | * First release 59 | * Fix error with unknown line number 60 | * Update documentation 61 | 62 | #### 1.0.0 63 | * Create plugin 64 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Pawel Chomicki 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # linter-python package 2 | 3 | Plugin to lint python files. Whole logic based on pylama and pylama-pylint applications. 4 | 5 | ![Package usage](https://raw.githubusercontent.com/pchomik/linter-python-doc/master/img/example.gif) 6 | 7 | ## Requirements 8 | 9 | * python >= 2.7 10 | * pylama >= 7.3.3 11 | * pylama-pylint (optional) 12 | 13 | ## Atom linters 14 | 15 | * [Atom Linters](http://atomlinter.github.io/) 16 | 17 | #### Linters for python 18 | 19 | * [linter-python](https://atom.io/packages/linter-python) 20 | * [linter-pep8](https://atom.io/packages/linter-pep8) 21 | * [linter-pydocstyle](https://atom.io/packages/linter-pydocstyle) 22 | * [linter-flake8](https://atom.io/packages/linter-flake8) 23 | * [linter-pylama](https://atom.io/packages/linter-pylama) 24 | 25 | ## Plugin installation 26 | 27 | #### Atom plugin installation 28 | 29 | ![Package usage](https://raw.githubusercontent.com/pchomik/linter-python-doc/master/img/install.gif) 30 | 31 | * Go to Settings -> Install 32 | * Type "linter-python" 33 | * Press "Install" 34 | 35 | #### Pylama installation 36 | 37 | ``` 38 | pip install pylama pylama-pylint 39 | ``` 40 | 41 | If pip is something new for you please look [here](https://pip.pypa.io/en/stable/installing/) for more detail. 42 | 43 | ## Plugin configuration 44 | 45 | #### Basic plugin configuration 46 | 47 | ![Package usage](https://raw.githubusercontent.com/pchomik/linter-python-doc/master/img/config.gif) 48 | 49 | * Go to Settings -> Packages 50 | * Type "linter-python" and go to plugin settings 51 | * Set path to pylama binary e.g. /usr/bin/pylama 52 | * Select needed pylama options 53 | 54 | #### Options added in 3.0.4 version 55 | 56 | ![Package usage](https://raw.githubusercontent.com/pchomik/linter-python-doc/master/img/3.0.4.gif) 57 | 58 | * Atom API was used to select error 59 | * URL to error description 60 | 61 | #### Plugin configuration vs. performance 62 | 63 | Please be informed that plugin has to create temporary files to lint file in the fly. In case of any performance issues please try 64 | to change trigger option to "File saved". For such option temporary files are not needed. 65 | 66 | ## Pylama related topics 67 | 68 | #### Pylama results depend on plugin order 69 | 70 | It was discovered that pylama plugin order may change lint results. Issue is under investigated and will be reported 71 | to pylama project as soon as I get time to create test scenarios. 72 | 73 | Tests show that the most trusted configuration is: mccabe,pyflakes,pylint,pep8,pep257 74 | 75 | #### Pyflakes plugin may change pylama result 76 | 77 | New issue was created in pylama project. Pylama results are not constant when pyflakes plugin is enabled. Issue is visible with Python 3.5.1 78 | 79 | Issue details are available [here](https://github.com/klen/pylama/issues/67). 80 | 81 | ## Lint errors 82 | 83 | Starting from plugin version 3.0.0 lint output provides link to error description available on GitHub [project](https://github.com/pchomik/linter-python-doc/blob/master/errors/). 84 | 85 | Thanks to @linickx who created all pages. Please provide more pull requests if you like to create single place for all python defined errors. 86 | 87 | ## Contribution 88 | 89 | Pull requests, issues, issue investigation, reviews are more than welcome. 90 | 91 | ## Contributors 92 | 93 | * @linickx 94 | * @Arcanemagus 95 | * @Zebradil 96 | 97 | ## License 98 | 99 | Package license is available [here](https://raw.githubusercontent.com/pchomik/linter-python/master/LICENSE.md) 100 | 101 | ## Contact 102 | 103 | Please create issue in case of any question or feature request. 104 | 105 | ## Changelog 106 | 107 | This section contains changes from last 3 releases. 108 | 109 | Full list of changes is available [here](https://raw.githubusercontent.com/pchomik/linter-python/master/CHANGELOG.md) 110 | 111 | #### 3.1.2 112 | * (#37) Fix issue: Cannot read property 'getPath' of undefined 113 | 114 | #### 3.1.1 115 | * Update release notes and readme file 116 | 117 | #### 3.1.0 118 | * (#31) Execution finished with error because of pylama exit code change 119 | 120 | #### 3.0.5 121 | * (#28) Add cache functionality 122 | * (#25) Remove underline options from plugin configuration 123 | * (#27) Documentation update 124 | * (#26) Regenerate new plugin exaples 125 | -------------------------------------------------------------------------------- /img/config.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pchomik/linter-python/15b0e636b0f26a4bff5e14c443ae9f7d26c10080/img/config.gif -------------------------------------------------------------------------------- /img/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pchomik/linter-python/15b0e636b0f26a4bff5e14c443ae9f7d26c10080/img/example.gif -------------------------------------------------------------------------------- /img/install.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pchomik/linter-python/15b0e636b0f26a4bff5e14c443ae9f7d26c10080/img/install.gif -------------------------------------------------------------------------------- /lib/cache.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var logger_1 = require('./logger'); 3 | var logger = logger_1.Logger.getInstance(); 4 | var Cache = (function () { 5 | function Cache() { 6 | this.messages = {}; 7 | if (Cache._instance) { 8 | throw new Error("Error: Instantiation failed: Use Logger.getInstance() instead of new."); 9 | } 10 | Cache._instance = this; 11 | } 12 | Cache.getInstance = function () { 13 | return Cache._instance; 14 | }; 15 | Cache.prototype.store = function (messages) { 16 | logger.log(">>> NEW MESSAGES STORED IN CACHE <<<"); 17 | this.messages[this.filePointer] = messages; 18 | }; 19 | Cache.prototype.get = function () { 20 | logger.log(">>> MESSAGES RETURNED FROM CACHE <<<"); 21 | if (!this.messages[this.filePointer]) { 22 | return []; 23 | } 24 | else { 25 | return this.messages[this.filePointer]; 26 | } 27 | }; 28 | Cache.prototype.set = function (filePath) { 29 | this.filePointer = filePath; 30 | logger.log(">>> CACHE SET FOR " + this.filePointer + " <<<"); 31 | }; 32 | Cache._instance = new Cache(); 33 | return Cache; 34 | }()); 35 | exports.Cache = Cache; 36 | //# sourceMappingURL=cache.js.map -------------------------------------------------------------------------------- /lib/cache.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":";AAAA,uBAAuB,UAAU,CAAC,CAAA;AAGlC,IAAM,MAAM,GAAU,eAAM,CAAC,WAAW,EAAE,CAAC;AAG3C;IAMI;QAHQ,aAAQ,GAAO,EAAE,CAAC;QAItB,EAAE,CAAA,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC7F,CAAC;QACD,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;IAC3B,CAAC;IAEa,iBAAW,GAAzB;QAEI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;IAC3B,CAAC;IAEM,qBAAK,GAAZ,UAAa,QAAQ;QACjB,MAAM,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACnD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC;IAC/C,CAAC;IAEM,mBAAG,GAAV;QACI,MAAM,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACnD,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YACnC,MAAM,CAAC,EAAE,CAAC;QACd,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3C,CAAC;IACL,CAAC;IAEM,mBAAG,GAAV,UAAW,QAAQ;QACf,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC;QAC5B,MAAM,CAAC,GAAG,CAAC,uBAAqB,IAAI,CAAC,WAAW,SAAM,CAAC,CAAC;IAC5D,CAAC;IAlCc,eAAS,GAAS,IAAI,KAAK,EAAE,CAAC;IAmCjD,YAAC;AAAD,CAAC,AApCD,IAoCC;AApCY,aAAK,QAoCjB,CAAA"} -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** Module to define plugin configuration and react on change. */ 3 | var logger_1 = require('./logger'); 4 | var CompositeDisposable = require('atom').CompositeDisposable; 5 | var logger = logger_1.Logger.getInstance(); 6 | /** Plugin runtime configuration. What is really set by the user when Atom is working */ 7 | var PluginRuntimeConfig = (function () { 8 | function PluginRuntimeConfig() { 9 | this.pylamaArgs = []; 10 | this.executablePath = ''; 11 | this.enableDebug = false; 12 | this.lintOnChange = false; 13 | this.lintOnSave = false; 14 | this.lintOnFly = false; 15 | this.optionsFileSet = false; 16 | this.underlineType = 'Whole line'; 17 | this.underlineSize = 2; 18 | this.limitToSingleInstance = true; 19 | this.linkColor = ""; 20 | this.initialConfg = this.initialConfg.bind(this); 21 | this.updateConfig = this.updateConfig.bind(this); 22 | this.subs = new CompositeDisposable(); 23 | this.subs.add(atom.config.observe('linter-python.executablePath', {}, this.updateConfig)); 24 | this.subs.add(atom.config.observe('linter-python.withPep8', {}, this.updateConfig)); 25 | this.subs.add(atom.config.observe('linter-python.withPep257', {}, this.updateConfig)); 26 | this.subs.add(atom.config.observe('linter-python.withMcCabe', {}, this.updateConfig)); 27 | this.subs.add(atom.config.observe('linter-python.withPylint', {}, this.updateConfig)); 28 | this.subs.add(atom.config.observe('linter-python.withPyflakes', {}, this.updateConfig)); 29 | this.subs.add(atom.config.observe('linter-python.ignoreCodes', {}, this.updateConfig)); 30 | this.subs.add(atom.config.observe('linter-python.skipFiles', {}, this.updateConfig)); 31 | this.subs.add(atom.config.observe('linter-python.force', {}, this.updateConfig)); 32 | this.subs.add(atom.config.observe('linter-python.optionsFile', {}, this.updateConfig)); 33 | this.subs.add(atom.config.observe('linter-python.enableDebug', {}, this.updateConfig)); 34 | this.subs.add(atom.config.observe('linter-python.lintTrigger', {}, this.updateConfig)); 35 | this.subs.add(atom.config.observe('linter-python.underlineSize', {}, this.updateConfig)); 36 | this.subs.add(atom.config.observe('linter-python.underlineType', {}, this.updateConfig)); 37 | this.subs.add(atom.config.observe('linter-python.limitToSingleInstance', {}, this.updateConfig)); 38 | this.subs.add(atom.config.observe('linter-python.linkColor', {}, this.updateConfig)); 39 | } 40 | /** Set default cofiguration values */ 41 | PluginRuntimeConfig.prototype.initialConfg = function () { 42 | var linters = []; 43 | this.pylamaArgs = []; 44 | this.optionsFileSet = false; 45 | this.executablePath = this.readConfigValue('executablePath'); 46 | this.limitToSingleInstance = this.readConfigValue('limitToSingleInstance'); 47 | this.linkColor = this.readConfigValue('linkColor'); 48 | this.underlineType = this.readConfigValue('underlineType'); 49 | if (this.underlineType == 'Only place with error') { 50 | this.underlineSize = this.readConfigValue('underlineSize'); 51 | } 52 | var enabledDebug = this.readConfigValue('enableDebug'); 53 | if (enabledDebug) { 54 | logger.enableLogger(); 55 | } 56 | else { 57 | logger.disableLogger(); 58 | } 59 | var withMcCabe = this.readConfigValue('withMcCabe'); 60 | if (withMcCabe) { 61 | linters.push('mccabe'); 62 | } 63 | var withPyflakes = this.readConfigValue('withPyflakes'); 64 | if (withPyflakes) { 65 | linters.push('pyflakes'); 66 | } 67 | var withPylint = this.readConfigValue('withPylint'); 68 | if (withPylint) { 69 | linters.push('pylint'); 70 | } 71 | var withPep8 = this.readConfigValue('withPep8'); 72 | if (withPep8) { 73 | linters.push('pep8'); 74 | } 75 | var withPep257 = this.readConfigValue('withPep257'); 76 | if (withPep257) { 77 | linters.push('pep257'); 78 | } 79 | if (linters.length > 0) { 80 | this.pylamaArgs.push('-l'); 81 | this.pylamaArgs.push(linters.join()); 82 | } 83 | var skipFiles = this.readConfigValue('skipFiles'); 84 | if (skipFiles.length > 0) { 85 | this.pylamaArgs.push('--skip'); 86 | this.pylamaArgs.push(skipFiles); 87 | } 88 | var ignoreCodes = this.readConfigValue('ignoreCodes'); 89 | if (ignoreCodes.length > 0) { 90 | this.pylamaArgs.push('-i'); 91 | this.pylamaArgs.push(ignoreCodes); 92 | } 93 | var optionsFile = this.readConfigValue('optionsFile'); 94 | if (optionsFile.length > 0) { 95 | this.optionsFileSet = true; 96 | this.pylamaArgs.push('-o'); 97 | this.pylamaArgs.push(optionsFile); 98 | } 99 | var force = this.readConfigValue('force'); 100 | if (force) { 101 | this.pylamaArgs.push('-F'); 102 | } 103 | var lintTrigger = this.readConfigValue('lintTrigger'); 104 | if (lintTrigger == 'File saved') { 105 | this.lintOnSave = true; 106 | this.lintOnFly = false; 107 | } 108 | else if (lintTrigger == 'File modified') { 109 | this.lintOnSave = false; 110 | this.lintOnFly = true; 111 | } 112 | else if (lintTrigger == 'File saved or modified') { 113 | this.lintOnSave = true; 114 | this.lintOnFly = true; 115 | } 116 | }; 117 | /** Method to simplify variable reading */ 118 | PluginRuntimeConfig.prototype.readConfigValue = function (value) { 119 | try { 120 | return atom.config.get("linter-python." + value); 121 | } 122 | catch (err) { 123 | console.log(err); 124 | return ''; 125 | } 126 | }; 127 | /** Method to update configuration after value changing */ 128 | PluginRuntimeConfig.prototype.updateConfig = function (value) { 129 | this.initialConfg(); 130 | }; 131 | PluginRuntimeConfig.prototype.logCurrentState = function () { 132 | logger.log(">>> PLUGIN INITIAL CONFIGURATION <<<"); 133 | logger.log("> pylamaArgs = " + this.pylamaArgs); 134 | logger.log("> executablePath = " + this.executablePath); 135 | logger.log("> enableDebug = " + this.enableDebug); 136 | logger.log("> lintOnChange = " + this.lintOnChange); 137 | logger.log("> linkOnFly = " + this.lintOnFly); 138 | logger.log("> lintOnSave = " + this.lintOnSave); 139 | logger.log("> optionsFileSet = " + this.optionsFileSet); 140 | logger.log("> underlineType = " + this.underlineType); 141 | logger.log("> underlineSize = " + this.underlineSize); 142 | logger.log("> limitToSingleInstance = " + this.limitToSingleInstance); 143 | logger.log("> linkColor = " + this.linkColor); 144 | logger.log('>>> END <<<'); 145 | }; 146 | return PluginRuntimeConfig; 147 | }()); 148 | exports.PluginRuntimeConfig = PluginRuntimeConfig; 149 | //# sourceMappingURL=config.js.map -------------------------------------------------------------------------------- /lib/config.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /lib/init.js: -------------------------------------------------------------------------------- 1 | /** Plugin initialization needed by Atom editor and linter plugin. */ 2 | "use strict"; 3 | var linter_1 = require('./linter'); 4 | var logger_1 = require('./logger'); 5 | var logger = logger_1.Logger.getInstance(); 6 | module.exports = { 7 | activate: function (state) { 8 | require('atom-package-deps').install('linter-python'); 9 | logger.log(">>> PACKAGE \"python-linter\" ACTIVATED <<<"); 10 | }, 11 | deactivate: function () { 12 | logger.log(">>> PACKAGE \"python-linter\" DEACTIVATED <<<"); 13 | }, 14 | provideLinter: function () { 15 | var linter = new linter_1.PluginLinter(); 16 | var provider = { 17 | name: 'Python Linter', 18 | grammarScopes: ['source.python'], 19 | scope: 'file', 20 | lintOnFly: true, 21 | lint: linter.lint, 22 | }; 23 | return provider; 24 | } 25 | }; 26 | //# sourceMappingURL=init.js.map -------------------------------------------------------------------------------- /lib/init.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,qEAAqE;;AAIrE,uBAA6B,UAAU,CAAC,CAAA;AACxC,uBAAuB,UAAU,CAAC,CAAA;AAElC,IAAM,MAAM,GAAU,eAAM,CAAC,WAAW,EAAE,CAAC;AAE3C,iBAAS;IACL,QAAQ,YAAC,KAAK;QACV,OAAO,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACtD,MAAM,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;IAC9D,CAAC;IAED,UAAU;QACN,MAAM,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAChE,CAAC;IAED,aAAa;QACT,IAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;QAClC,IAAM,QAAQ,GAAG;YACb,IAAI,EAAE,eAAe;YACrB,aAAa,EAAE,CAAC,eAAe,CAAC;YAChC,KAAK,EAAE,MAAM;YACb,SAAS,EAAE,IAAI;YACf,IAAI,EAAE,MAAM,CAAC,IAAI;SACpB,CAAC;QACF,MAAM,CAAC,QAAQ,CAAC;IACpB,CAAC;CACJ,CAAA"} -------------------------------------------------------------------------------- /lib/linter.js: -------------------------------------------------------------------------------- 1 | /** Main body to handle whole process. */ 2 | "use strict"; 3 | var runner_1 = require('./runner'); 4 | var config_1 = require('./config'); 5 | var parser_1 = require('./parser'); 6 | var logger_1 = require('./logger'); 7 | var cache_1 = require('./cache'); 8 | var util_1 = require('./util'); 9 | var fs = require('fs'); 10 | var os = require('os'); 11 | var temp = require('temp'); 12 | var path = require('path'); 13 | var logger = logger_1.Logger.getInstance(); 14 | var cache = cache_1.Cache.getInstance(); 15 | var PluginLinter = (function () { 16 | function PluginLinter() { 17 | this.runtimeConfig = new config_1.PluginRuntimeConfig(); 18 | this.runtimeConfig.initialConfg(); 19 | this.runtimeConfig.logCurrentState(); 20 | this.runner = new runner_1.ProcessRunner(); 21 | this.tempFileHandler = new util_1.TempFileHandler(); 22 | this.running = false; 23 | this.tempFile = null; 24 | this.lint = this.lint.bind(this); 25 | } 26 | PluginLinter.prototype.lint = function () { 27 | var textEditor = atom.workspace.getActiveTextEditor(); 28 | if (!atom.workspace.isTextEditor(textEditor)) { 29 | return Promise.resolve(cache.get()); 30 | } 31 | var filePath = textEditor.getPath(); 32 | if (!filePath) { 33 | return Promise.resolve(cache.get()); 34 | } 35 | var projectDir = this.calculateProjectDir(filePath); 36 | var cmd = this.runtimeConfig.executablePath; 37 | var args = []; 38 | cache.set(filePath); 39 | if (this.running == true && this.runtimeConfig.limitToSingleInstance == true) { 40 | logger.log(">>> EXECUTION SKIPPED <<<"); 41 | return Promise.resolve(cache.get()); 42 | } 43 | logger.log(">>> INPUT FOR LINTING <<<"); 44 | logger.log("> filePath = " + filePath); 45 | logger.log("> projectDir = " + projectDir); 46 | logger.log("> cmd = " + cmd); 47 | logger.log("> args = []"); 48 | logger.log('>>> END <<<'); 49 | if (!util_1.canExecute(cmd)) { 50 | atom.notifications.addError("Provided path doesn't exist.\n\n" + cmd + "\n\nPlease fix pylama path or install latest version."); 51 | return Promise.resolve(cache.get()); 52 | } 53 | if (this.isForLintOnFly(textEditor)) { 54 | this.tempFile = this.tempFileHandler.create(textEditor.getText()); 55 | var parser = new parser_1.OnFlyParameterParser(); 56 | var result = parser.parse(projectDir, this.tempFile.path, this.runtimeConfig); 57 | args = result.args; 58 | projectDir = result.projectDir; 59 | } 60 | else if (this.isForLintOnSave(textEditor)) { 61 | var parser = new parser_1.SaveParameterParser(); 62 | var result = parser.parse(projectDir, filePath, this.runtimeConfig); 63 | args = result.args; 64 | projectDir = result.projectDir; 65 | } 66 | else { 67 | return Promise.resolve(cache.get()); 68 | } 69 | logger.log(">>> NEW ARGS <<<"); 70 | logger.log("> " + args); 71 | logger.log('>>> END <<<'); 72 | return this.runner.run(textEditor, this.runtimeConfig, projectDir, cmd, args, this.running, this.tempFile); 73 | }; 74 | PluginLinter.prototype.calculateProjectDir = function (filePath) { 75 | var projectDir = atom.project.relativizePath(filePath)[0]; 76 | if (projectDir) { 77 | return projectDir; 78 | } 79 | var fileDir = path.dirname(filePath); 80 | if (fileDir) { 81 | return fileDir; 82 | } 83 | return os.tmpdir(); 84 | }; 85 | PluginLinter.prototype.isForLintOnFly = function (textEditor) { 86 | if (this.runtimeConfig.lintOnFly && textEditor.isModified()) { 87 | return true; 88 | } 89 | else { 90 | return false; 91 | } 92 | }; 93 | PluginLinter.prototype.isForLintOnSave = function (textEditor) { 94 | if (this.runtimeConfig.lintOnSave && !textEditor.isModified()) { 95 | return true; 96 | } 97 | else { 98 | return false; 99 | } 100 | }; 101 | return PluginLinter; 102 | }()); 103 | exports.PluginLinter = PluginLinter; 104 | //# sourceMappingURL=linter.js.map -------------------------------------------------------------------------------- /lib/linter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"linter.js","sourceRoot":"","sources":["../src/linter.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /lib/logger.js: -------------------------------------------------------------------------------- 1 | /** Module to log debug prints if debug prints are enabled */ 2 | "use strict"; 3 | var Logger = (function () { 4 | function Logger() { 5 | this._enabled = false; 6 | if (Logger._instance) { 7 | throw new Error("Error: Instantiation failed: Use Logger.getInstance() instead of new."); 8 | } 9 | Logger._instance = this; 10 | } 11 | Logger.getInstance = function () { 12 | return Logger._instance; 13 | }; 14 | Logger.prototype.enableLogger = function () { 15 | if (!this._enabled) { 16 | this._enabled = true; 17 | console.log(">>> DEBUG ENABLED <<<"); 18 | } 19 | }; 20 | Logger.prototype.disableLogger = function () { 21 | if (this._enabled) { 22 | this._enabled = false; 23 | console.log(">>> DEBUG DISABLED <<<"); 24 | } 25 | }; 26 | Logger.prototype.log = function (message) { 27 | if (this._enabled) { 28 | console.log(message); 29 | } 30 | }; 31 | Logger._instance = new Logger(); 32 | return Logger; 33 | }()); 34 | exports.Logger = Logger; 35 | //# sourceMappingURL=logger.js.map -------------------------------------------------------------------------------- /lib/logger.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,6DAA6D;;AAE7D;IAMI;QAFQ,aAAQ,GAAW,KAAK,CAAC;QAG7B,EAAE,CAAA,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC7F,CAAC;QACD,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;IAC5B,CAAC;IAEa,kBAAW,GAAzB;QAEI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;IAC5B,CAAC;IAEM,6BAAY,GAAnB;QACI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACzC,CAAC;IACL,CAAC;IAEM,8BAAa,GAApB;QACI,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAChB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QAC1C,CAAC;IACL,CAAC;IAEM,oBAAG,GAAV,UAAW,OAAO;QACd,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;IACL,CAAC;IAlCc,gBAAS,GAAU,IAAI,MAAM,EAAE,CAAC;IAmCnD,aAAC;AAAD,CAAC,AArCD,IAqCC;AArCY,cAAM,SAqClB,CAAA"} -------------------------------------------------------------------------------- /lib/parser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** Module responsible to read, parse message returned by pylama application. 3 | This module should return also link to github page where all errors 4 | are available.*/ 5 | var logger_1 = require('./logger'); 6 | var util_1 = require('./util'); 7 | var docUrl = 'https://github.com/pchomik/linter-python-doc/blob/master/errors/'; 8 | var genericRegexp = /(.*):(\d+):(\d+):\s(.\d+)\s*(.*)\[(.*)\]$/; // file:row:col:error:message:tool 9 | var pyflakesRegexp = /(.*):(\d+):(\d+):\s*(.*)\[(.*)\]$/; // file:row:col:message:tool 10 | var logger = logger_1.Logger.getInstance(); 11 | var path = require('path'); 12 | var atomLinter = require('atom-linter'); 13 | var MessageParser = (function () { 14 | function MessageParser() { 15 | } 16 | MessageParser.prototype.parseLines = function (data) { 17 | var results = []; 18 | var lines = data.split('\n'); 19 | for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) { 20 | var line = lines_1[_i]; 21 | var found = line.match(genericRegexp); 22 | if (found) { 23 | results.push({ 24 | 'fileName': found[1], 25 | 'row': Number(found[2]), 26 | 'col': Number(found[3]), 27 | 'error': found[4], 28 | 'message': found[5], 29 | 'tool': found[6] 30 | }); 31 | } 32 | else { 33 | found = line.match(pyflakesRegexp); 34 | if (found) { 35 | results.push({ 36 | 'fileName': found[1], 37 | 'row': Number(found[2]), 38 | 'col': Number(found[3]), 39 | 'error': '', 40 | 'message': found[4], 41 | 'tool': found[5] 42 | }); 43 | } 44 | } 45 | } 46 | return results; 47 | }; 48 | MessageParser.prototype.buildMessage = function (textEditor, result, config) { 49 | var line = textEditor.getBuffer().lineForRow(result.row - 1); 50 | var filePath = textEditor.getPath(); 51 | var resultType = 'Warning'; 52 | if (result.error.indexOf('E') > -1 || result.error.indexOf('F') > -1) { 53 | resultType = 'Error'; 54 | } 55 | var text = this.buildErrorText(result, config); 56 | var range = atomLinter.rangeFromLineNumber(textEditor, result.row - 1, result.col - 1); 57 | var message = { 58 | type: resultType, 59 | html: text, 60 | filePath: filePath, 61 | range: range, 62 | }; 63 | logger.log(">>> NEW MESSAGE <<"); 64 | logger.log("> type = " + message.type); 65 | logger.log("> html = " + message.html); 66 | logger.log("> filePath = " + message.filePath); 67 | logger.log("> range = " + message.range); 68 | logger.log(">>> END <<<"); 69 | return message; 70 | }; 71 | MessageParser.prototype.buildErrorText = function (result, config) { 72 | if (!result.tool) { 73 | return result.error + " " + result.message; 74 | } 75 | else if (result.tool == 'mccabe') { 76 | return result.error + " " + result.message + " [" + result.tool + "]"; 77 | } 78 | else { 79 | return "" + result.error + " " + result.message + " [" + result.tool + "]"; 80 | } 81 | }; 82 | return MessageParser; 83 | }()); 84 | exports.MessageParser = MessageParser; 85 | var SaveParameterParser = (function () { 86 | function SaveParameterParser() { 87 | } 88 | SaveParameterParser.prototype.parse = function (projectDir, filePath, config) { 89 | return { 90 | 'args': config.pylamaArgs.concat(['--sort', 'E,W,D', '-f', 'pep8', filePath]), 91 | 'projectDir': projectDir 92 | }; 93 | }; 94 | return SaveParameterParser; 95 | }()); 96 | exports.SaveParameterParser = SaveParameterParser; 97 | var OnFlyParameterParser = (function () { 98 | function OnFlyParameterParser() { 99 | } 100 | OnFlyParameterParser.prototype.parse = function (projectDir, filePath, config) { 101 | var pylama_options_file = path.join(projectDir, 'pylama.ini'); 102 | projectDir = path.dirname(filePath); 103 | if (util_1.canRead(pylama_options_file)) { 104 | return { 105 | 'args': config.pylamaArgs.concat(['--sort', 'E,W,D', '-o', pylama_options_file, '-f', 'pep8', filePath]), 106 | 'projectDir': projectDir 107 | }; 108 | } 109 | else { 110 | return { 111 | 'args': config.pylamaArgs.concat(['--sort', 'E,W,D', '-f', 'pep8', filePath]), 112 | 'projectDir': projectDir 113 | }; 114 | } 115 | }; 116 | return OnFlyParameterParser; 117 | }()); 118 | exports.OnFlyParameterParser = OnFlyParameterParser; 119 | //# sourceMappingURL=parser.js.map -------------------------------------------------------------------------------- /lib/parser.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /lib/runner.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** Module to handle process execution. */ 3 | var logger_1 = require('./logger'); 4 | var parser_1 = require('./parser'); 5 | var cache_1 = require('./cache'); 6 | var cp = require('child-process-es6-promise'); 7 | var logger = logger_1.Logger.getInstance(); 8 | var cache = cache_1.Cache.getInstance(); 9 | /** Class to execute process and return read output. */ 10 | var ProcessRunner = (function () { 11 | function ProcessRunner() { 12 | this.parser = new parser_1.MessageParser(); 13 | } 14 | ProcessRunner.prototype.run = function (textEditor, config, projectDir, cmd, args, runningFlag, tempFile) { 15 | var _this = this; 16 | return new Promise(function (resolve) { 17 | var messages = []; 18 | cp.spawn(cmd, args, { cwd: projectDir }) 19 | .then(function (result) { 20 | // Pylama's exit code is 0 when there are no linting errors. 21 | logger.log(">>> NO ERRORS <<<"); 22 | logger.log(">>> RAW OUTPUT <<<"); 23 | logger.log(result.stdout); 24 | logger.log(">>> END <<<"); 25 | return resolve(messages); 26 | }) 27 | .catch(function (error) { 28 | // Pylama's exit code is 1 when there are linting errors. 29 | logger.log(">>> RAW OUTPUT <<<"); 30 | logger.log(error.stdout); 31 | logger.log(">>> END <<<"); 32 | var parsedLines = _this.parser.parseLines(error.stdout); 33 | for (var _i = 0, parsedLines_1 = parsedLines; _i < parsedLines_1.length; _i++) { 34 | var parsedLine = parsedLines_1[_i]; 35 | var message = _this.parser.buildMessage(textEditor, parsedLine, config); 36 | messages.unshift(message); 37 | } 38 | runningFlag = false; 39 | if (tempFile) { 40 | tempFile.clean(); 41 | } 42 | cache.store(messages); 43 | return resolve(messages); 44 | }); 45 | }); 46 | }; 47 | return ProcessRunner; 48 | }()); 49 | exports.ProcessRunner = ProcessRunner; 50 | //# sourceMappingURL=runner.js.map -------------------------------------------------------------------------------- /lib/runner.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":";AAAA,0CAA0C;AAC1C,uBAAuB,UAAU,CAAC,CAAA;AAClC,uBAA8B,UAAU,CAAC,CAAA;AACzC,sBAAsB,SAAS,CAAC,CAAA;AAEhC,IAAM,EAAE,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;AAChD,IAAM,MAAM,GAAU,eAAM,CAAC,WAAW,EAAE,CAAC;AAC3C,IAAM,KAAK,GAAS,aAAK,CAAC,WAAW,EAAE,CAAC;AAIxC,uDAAuD;AACvD;IAII;QACI,IAAI,CAAC,MAAM,GAAG,IAAI,sBAAa,EAAE,CAAC;IACtC,CAAC;IACD,2BAAG,GAAH,UAAI,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ;QAApE,iBA8BC;QA7BG,MAAM,CAAC,IAAI,OAAO,CAAC,UAAC,OAAO;YACvB,IAAI,QAAQ,GAAG,EAAE,CAAA;YACjB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAC,GAAG,EAAE,UAAU,EAAC,CAAC;iBACrC,IAAI,CAAC,UAAC,MAAM;gBACT,4DAA4D;gBAC5D,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;gBAChC,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;gBACjC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC1B,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBAC1B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC7B,CAAC,CAAC;iBACD,KAAK,CAAC,UAAC,KAAK;gBACT,yDAAyD;gBACzD,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;gBACjC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACzB,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBAC1B,IAAI,WAAW,GAAG,KAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACvD,GAAG,CAAC,CAAmB,UAAW,EAAX,2BAAW,EAAX,yBAAW,EAAX,IAAW,CAAC;oBAA9B,IAAI,UAAU,oBAAA;oBACf,IAAI,OAAO,GAAG,KAAI,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;oBACvE,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;iBAC7B;gBACD,WAAW,GAAG,KAAK,CAAC;gBACpB,EAAE,CAAA,CAAC,QAAQ,CAAC,CAAC,CAAC;oBACV,QAAQ,CAAC,KAAK,EAAE,CAAC;gBACrB,CAAC;gBACD,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACtB,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC7B,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAA;IACN,CAAC;IACL,oBAAC;AAAD,CAAC,AAtCD,IAsCC;AAtCY,qBAAa,gBAsCzB,CAAA"} -------------------------------------------------------------------------------- /lib/util.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var logger_1 = require('./logger'); 3 | var temp = require('temp'); 4 | var fs = require('fs'); 5 | var logger = logger_1.Logger.getInstance(); 6 | var TempFileHandler = (function () { 7 | function TempFileHandler() { 8 | } 9 | TempFileHandler.prototype.create = function (text) { 10 | var tempFile = temp.openSync({ suffix: '.py' }); 11 | fs.writeSync(tempFile.fd, text); 12 | fs.closeSync(tempFile.fd); 13 | return new TempFileWrapper(tempFile); 14 | }; 15 | return TempFileHandler; 16 | }()); 17 | exports.TempFileHandler = TempFileHandler; 18 | var TempFileWrapper = (function () { 19 | function TempFileWrapper(tempFile) { 20 | this.tempFile = tempFile; 21 | this.path = tempFile.path; 22 | } 23 | TempFileWrapper.prototype.clean = function () { 24 | if (this.tempFile == null) { 25 | return; 26 | } 27 | fs.unlink(this.path); 28 | this.path = null; 29 | this.tempFile = null; 30 | }; 31 | return TempFileWrapper; 32 | }()); 33 | exports.TempFileWrapper = TempFileWrapper; 34 | function canExecute(path) { 35 | logger.log(">>> EXECUTE CHECK <<<"); 36 | try { 37 | fs.accessSync(path, fs.R_OK | fs.X_OK); 38 | logger.log("> Path can be executed"); 39 | logger.log(">>> END <<<"); 40 | return true; 41 | } 42 | catch (err) { 43 | logger.log("> Path can not be executed:"); 44 | logger.log(err); 45 | logger.log(">>> END <<<"); 46 | return false; 47 | } 48 | } 49 | exports.canExecute = canExecute; 50 | function canRead(path) { 51 | logger.log(">>> READ CHECK <<<"); 52 | try { 53 | fs.accessSync(path, fs.R_OK); 54 | logger.log("> Path can be read"); 55 | logger.log(">>> END <<<"); 56 | return true; 57 | } 58 | catch (err) { 59 | logger.log("> Path can not be read"); 60 | logger.log(err); 61 | logger.log(">>> END <<<"); 62 | return false; 63 | } 64 | } 65 | exports.canRead = canRead; 66 | //# sourceMappingURL=util.js.map -------------------------------------------------------------------------------- /lib/util.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";AAAA,uBAAuB,UAAU,CAAC,CAAA;AAElC,IAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAC7B,IAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACzB,IAAM,MAAM,GAAU,eAAM,CAAC,WAAW,EAAE,CAAC;AAG3C;IAAA;IASA,CAAC;IANG,gCAAM,GAAN,UAAO,IAAI;QACP,IAAI,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAC,MAAM,EAAE,KAAK,EAAC,CAAC,CAAC;QAC9C,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAChC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC1B,MAAM,CAAC,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;IACL,sBAAC;AAAD,CAAC,AATD,IASC;AATY,uBAAe,kBAS3B,CAAA;AAGD;IAII,yBAAY,QAAQ;QAChB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC9B,CAAC;IAED,+BAAK,GAAL;QACI,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC;YACxB,MAAM,CAAC;QACX,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACzB,CAAC;IAGL,sBAAC;AAAD,CAAC,AAnBD,IAmBC;AAnBY,uBAAe,kBAmB3B,CAAA;AAGD,oBAA2B,IAAI;IAC3B,MAAM,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACpC,IAAI,CAAC;QACD,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACrC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC;IAChB,CACA;IAAA,KAAK,CAAA,CAAC,GAAG,CAAC,CAAC,CAAC;QACR,MAAM,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAde,kBAAU,aAczB,CAAA;AAGD,iBAAwB,IAAI;IACxB,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACjC,IAAI,CAAC;QACD,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;QACzB,MAAM,CAAC,IAAI,CAAC;IAChB,CACA;IAAA,KAAK,CAAA,CAAC,GAAG,CAAC,CAAC,CAAC;QACR,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACrC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;QACzB,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAde,eAAO,UActB,CAAA"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linter-python", 3 | "main": "./lib/init", 4 | "version": "3.1.2", 5 | "description": "Linter for python files. Lint operation based on pylama application.", 6 | "repository": "https://github.com/pchomik/linter-python", 7 | "license": "MIT", 8 | "engines": { 9 | "atom": ">=1.0.0 <2.0.0" 10 | }, 11 | "scripts": { 12 | "start": "npm run tsc:w", 13 | "afterinstall": "typings install", 14 | "tsc": "tsc", 15 | "tsc:w": "tsc -w", 16 | "typings": "typings" 17 | }, 18 | "providedServices": { 19 | "linter": { 20 | "versions": { 21 | "1.0.0": "provideLinter" 22 | } 23 | } 24 | }, 25 | "dependencies": { 26 | "atom-package-deps": "^4.0.1", 27 | "child-process-es6-promise": "^1.0.0", 28 | "temp": "^0.8.3", 29 | "atom-linter": "^6.0.0" 30 | }, 31 | "package-deps": [ 32 | "linter" 33 | ], 34 | "devDependencies": { 35 | "typescript": "^1.8.10", 36 | "typings": "^1.0.4", 37 | "atom": "^1.0.0" 38 | }, 39 | "configSchema": { 40 | "executablePath": { 41 | "type": "string", 42 | "default": "pylama", 43 | "description": "Excutable path for external Pylama. Example: /usr/local/bin/pylama.", 44 | "order": 1 45 | }, 46 | "withPep8": { 47 | "type": "boolean", 48 | "default": false, 49 | "description": "Run pylama with pep8 linter.", 50 | "order": 2 51 | }, 52 | "withPep257": { 53 | "type": "boolean", 54 | "default": false, 55 | "description": "Run pylama with PEP257 linter.", 56 | "order": 3 57 | }, 58 | "withMcCabe": { 59 | "type": "boolean", 60 | "default": false, 61 | "description": "Run pylama with McCabe linter.", 62 | "order": 4 63 | }, 64 | "withPyflakes": { 65 | "type": "boolean", 66 | "default": false, 67 | "description": "Run pylama with Pyflakes linter.", 68 | "order": 5 69 | }, 70 | "withPylint": { 71 | "type": "boolean", 72 | "default": false, 73 | "description": "Run pylama with Pylint linter. To enable this option please execute following command: pip install pylama-pylint.", 74 | "order": 6 75 | }, 76 | "skipFiles": { 77 | "type": "string", 78 | "default": "", 79 | "description": "Skip files by masks (comma-separated, ex. */message,py,*/ignore.py).", 80 | "order": 7 81 | }, 82 | "ignoreCodes": { 83 | "type": "string", 84 | "default": "", 85 | "description": "Provided codes will be ignored by linters. Example: E111,E114,D101,D102,DW0311.", 86 | "order": 8 87 | }, 88 | "optionsFile": { 89 | "type": "string", 90 | "default": "", 91 | "description": "Path to configuration file. By default is /pylama.ini", 92 | "order": 9 93 | }, 94 | "force": { 95 | "type": "boolean", 96 | "default": false, 97 | "description": "Force code checking (if linter doesnt allow).", 98 | "order": 10 99 | }, 100 | "lintTrigger": { 101 | "type": "string", 102 | "default": "File saved", 103 | "enum": [ 104 | "File saved", 105 | "File modified", 106 | "File saved or modified" 107 | ], 108 | "description": "Defines when lint action should be triggered.", 109 | "order": 11 110 | }, 111 | "enableDebug": { 112 | "type": "boolean", 113 | "default": false, 114 | "description": "Enable debug console prints.", 115 | "order": 12 116 | }, 117 | "limitToSingleInstance": { 118 | "type": "boolean", 119 | "default": true, 120 | "description": "Limit how many pylama binaries can be executed. By default is set to single instance.", 121 | "order": 13 122 | }, 123 | "linkColor": { 124 | "type": "color", 125 | "default": "#bf6815", 126 | "description": "Link color for all errors/warning/types", 127 | "order": 14 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/cache.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from './logger'; 2 | 3 | 4 | const logger:Logger = Logger.getInstance(); 5 | 6 | 7 | export class Cache { 8 | private static _instance:Cache = new Cache(); 9 | 10 | private messages:any = {}; 11 | private filePointer: string; 12 | 13 | constructor() { 14 | if(Cache._instance){ 15 | throw new Error("Error: Instantiation failed: Use Logger.getInstance() instead of new."); 16 | } 17 | Cache._instance = this; 18 | } 19 | 20 | public static getInstance():Cache 21 | { 22 | return Cache._instance; 23 | } 24 | 25 | public store(messages) { 26 | logger.log(">>> NEW MESSAGES STORED IN CACHE <<<"); 27 | this.messages[this.filePointer] = messages; 28 | } 29 | 30 | public get() { 31 | logger.log(">>> MESSAGES RETURNED FROM CACHE <<<"); 32 | if (!this.messages[this.filePointer]) { 33 | return []; 34 | } else { 35 | return this.messages[this.filePointer]; 36 | } 37 | } 38 | 39 | public set(filePath) { 40 | this.filePointer = filePath; 41 | logger.log(`>>> CACHE SET FOR ${this.filePointer} <<<`); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | /** Module to define plugin configuration and react on change. */ 2 | import { Logger } from './logger'; 3 | 4 | const CompositeDisposable = require('atom').CompositeDisposable; 5 | const logger:Logger = Logger.getInstance(); 6 | 7 | declare var atom; 8 | 9 | 10 | /** Plugin runtime configuration. What is really set by the user when Atom is working */ 11 | export class PluginRuntimeConfig { 12 | 13 | pylamaArgs: any[] = []; 14 | executablePath: string = ''; 15 | enableDebug: boolean = false; 16 | lintOnChange: boolean = false; 17 | lintOnSave: boolean = false; 18 | lintOnFly: boolean = false; 19 | optionsFileSet: boolean = false; 20 | underlineType: string = 'Whole line'; 21 | underlineSize: number = 2; 22 | limitToSingleInstance: boolean = true; 23 | linkColor: any = ""; 24 | subs: any; 25 | 26 | constructor() { 27 | 28 | this.initialConfg = this.initialConfg.bind(this); 29 | this.updateConfig = this.updateConfig.bind(this); 30 | 31 | this.subs = new CompositeDisposable(); 32 | this.subs.add(atom.config.observe('linter-python.executablePath', {}, this.updateConfig)); 33 | this.subs.add(atom.config.observe('linter-python.withPep8', {}, this.updateConfig)); 34 | this.subs.add(atom.config.observe('linter-python.withPep257', {}, this.updateConfig)); 35 | this.subs.add(atom.config.observe('linter-python.withMcCabe', {}, this.updateConfig)); 36 | this.subs.add(atom.config.observe('linter-python.withPylint', {}, this.updateConfig)); 37 | this.subs.add(atom.config.observe('linter-python.withPyflakes', {}, this.updateConfig)); 38 | this.subs.add(atom.config.observe('linter-python.ignoreCodes', {}, this.updateConfig)); 39 | this.subs.add(atom.config.observe('linter-python.skipFiles', {}, this.updateConfig)); 40 | this.subs.add(atom.config.observe('linter-python.force', {}, this.updateConfig)); 41 | this.subs.add(atom.config.observe('linter-python.optionsFile', {}, this.updateConfig)); 42 | this.subs.add(atom.config.observe('linter-python.enableDebug', {}, this.updateConfig)); 43 | this.subs.add(atom.config.observe('linter-python.lintTrigger', {}, this.updateConfig)); 44 | this.subs.add(atom.config.observe('linter-python.underlineSize', {}, this.updateConfig)); 45 | this.subs.add(atom.config.observe('linter-python.underlineType', {}, this.updateConfig)); 46 | this.subs.add(atom.config.observe('linter-python.limitToSingleInstance', {}, this.updateConfig)); 47 | this.subs.add(atom.config.observe('linter-python.linkColor', {}, this.updateConfig)); 48 | } 49 | 50 | /** Set default cofiguration values */ 51 | initialConfg() { 52 | let linters = []; 53 | 54 | this.pylamaArgs = []; 55 | this.optionsFileSet = false; 56 | 57 | this.executablePath = this.readConfigValue('executablePath'); 58 | this.limitToSingleInstance = this.readConfigValue('limitToSingleInstance'); 59 | this.linkColor = this.readConfigValue('linkColor'); 60 | 61 | this.underlineType = this.readConfigValue('underlineType'); 62 | if (this.underlineType == 'Only place with error') { 63 | this.underlineSize = this.readConfigValue('underlineSize'); 64 | } 65 | 66 | let enabledDebug = this.readConfigValue('enableDebug'); 67 | if (enabledDebug) { 68 | logger.enableLogger(); 69 | } else { 70 | logger.disableLogger(); 71 | } 72 | 73 | let withMcCabe = this.readConfigValue('withMcCabe'); 74 | if (withMcCabe) { 75 | linters.push('mccabe'); 76 | } 77 | 78 | let withPyflakes = this.readConfigValue('withPyflakes'); 79 | if (withPyflakes) { 80 | linters.push('pyflakes'); 81 | } 82 | 83 | let withPylint = this.readConfigValue('withPylint'); 84 | if (withPylint) { 85 | linters.push('pylint'); 86 | } 87 | 88 | let withPep8 = this.readConfigValue('withPep8'); 89 | if (withPep8) { 90 | linters.push('pep8'); 91 | } 92 | 93 | let withPep257 = this.readConfigValue('withPep257'); 94 | if (withPep257) { 95 | linters.push('pep257'); 96 | } 97 | 98 | if (linters.length > 0) { 99 | this.pylamaArgs.push('-l'); 100 | this.pylamaArgs.push(linters.join()); 101 | } 102 | 103 | let skipFiles = this.readConfigValue('skipFiles'); 104 | if (skipFiles.length > 0) { 105 | this.pylamaArgs.push('--skip'); 106 | this.pylamaArgs.push(skipFiles); 107 | } 108 | 109 | let ignoreCodes = this.readConfigValue('ignoreCodes'); 110 | if (ignoreCodes.length > 0) { 111 | this.pylamaArgs.push('-i'); 112 | this.pylamaArgs.push(ignoreCodes); 113 | } 114 | 115 | let optionsFile = this.readConfigValue('optionsFile'); 116 | if (optionsFile.length > 0) { 117 | this.optionsFileSet = true; 118 | this.pylamaArgs.push('-o'); 119 | this.pylamaArgs.push(optionsFile); 120 | } 121 | 122 | let force = this.readConfigValue('force'); 123 | if (force) { 124 | this.pylamaArgs.push('-F'); 125 | } 126 | 127 | let lintTrigger = this.readConfigValue('lintTrigger'); 128 | if (lintTrigger == 'File saved') { 129 | this.lintOnSave = true; 130 | this.lintOnFly = false; 131 | } 132 | else if (lintTrigger == 'File modified') { 133 | this.lintOnSave = false; 134 | this.lintOnFly = true; 135 | } 136 | else if (lintTrigger == 'File saved or modified') { 137 | this.lintOnSave = true; 138 | this.lintOnFly = true; 139 | } 140 | } 141 | 142 | /** Method to simplify variable reading */ 143 | readConfigValue(value) { 144 | try { 145 | return atom.config.get(`linter-python.${value}`); 146 | } 147 | catch(err) { 148 | console.log(err); 149 | return ''; 150 | } 151 | } 152 | 153 | /** Method to update configuration after value changing */ 154 | updateConfig(value) { 155 | this.initialConfg(); 156 | } 157 | 158 | public logCurrentState() { 159 | logger.log(">>> PLUGIN INITIAL CONFIGURATION <<<"); 160 | logger.log(`> pylamaArgs = ${this.pylamaArgs}`); 161 | logger.log(`> executablePath = ${this.executablePath}`); 162 | logger.log(`> enableDebug = ${this.enableDebug}`); 163 | logger.log(`> lintOnChange = ${this.lintOnChange}`); 164 | logger.log(`> linkOnFly = ${this.lintOnFly}`); 165 | logger.log(`> lintOnSave = ${this.lintOnSave}`); 166 | logger.log(`> optionsFileSet = ${this.optionsFileSet}`); 167 | logger.log(`> underlineType = ${this.underlineType}`); 168 | logger.log(`> underlineSize = ${this.underlineSize}`); 169 | logger.log(`> limitToSingleInstance = ${this.limitToSingleInstance}`); 170 | logger.log(`> linkColor = ${this.linkColor}`); 171 | logger.log('>>> END <<<'); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/init.ts: -------------------------------------------------------------------------------- 1 | /** Plugin initialization needed by Atom editor and linter plugin. */ 2 | 3 | declare var atom; 4 | 5 | import { PluginLinter } from './linter'; 6 | import { Logger } from './logger'; 7 | 8 | const logger:Logger = Logger.getInstance(); 9 | 10 | export = { 11 | activate(state) { 12 | require('atom-package-deps').install('linter-python'); 13 | logger.log(">>> PACKAGE \"python-linter\" ACTIVATED <<<"); 14 | }, 15 | 16 | deactivate() { 17 | logger.log(">>> PACKAGE \"python-linter\" DEACTIVATED <<<"); 18 | }, 19 | 20 | provideLinter() { 21 | const linter = new PluginLinter(); 22 | const provider = { 23 | name: 'Python Linter', 24 | grammarScopes: ['source.python'], 25 | scope: 'file', 26 | lintOnFly: true, 27 | lint: linter.lint, 28 | }; 29 | return provider; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/linter.ts: -------------------------------------------------------------------------------- 1 | /** Main body to handle whole process. */ 2 | 3 | import { ProcessRunner } from './runner'; 4 | import { PluginRuntimeConfig } from './config'; 5 | import { SaveParameterParser, OnFlyParameterParser } from './parser'; 6 | import { Logger } from './logger'; 7 | import { Cache } from './cache'; 8 | import { TempFileHandler, canExecute, TempFileWrapper } from './util'; 9 | 10 | const fs = require('fs'); 11 | const os = require('os'); 12 | const temp = require('temp'); 13 | const path = require('path'); 14 | const logger:Logger = Logger.getInstance(); 15 | const cache:Cache = Cache.getInstance(); 16 | 17 | declare var atom; 18 | 19 | export class PluginLinter { 20 | 21 | runtimeConfig: PluginRuntimeConfig; 22 | runner: ProcessRunner; 23 | tempFileHandler: TempFileHandler; 24 | running: boolean; 25 | tempFile: TempFileWrapper; 26 | lastFilePath: String; 27 | 28 | constructor() { 29 | this.runtimeConfig = new PluginRuntimeConfig(); 30 | this.runtimeConfig.initialConfg(); 31 | this.runtimeConfig.logCurrentState(); 32 | this.runner = new ProcessRunner(); 33 | this.tempFileHandler = new TempFileHandler(); 34 | this.running = false; 35 | this.tempFile = null; 36 | 37 | this.lint = this.lint.bind(this); 38 | } 39 | 40 | lint() { 41 | let textEditor = atom.workspace.getActiveTextEditor(); 42 | if (!atom.workspace.isTextEditor(textEditor)) { 43 | return Promise.resolve(cache.get()); 44 | } 45 | let filePath = textEditor.getPath(); 46 | if (!filePath) { 47 | return Promise.resolve(cache.get()); 48 | } 49 | let projectDir = this.calculateProjectDir(filePath); 50 | let cmd = this.runtimeConfig.executablePath; 51 | let args = []; 52 | 53 | cache.set(filePath); 54 | 55 | if (this.running == true && this.runtimeConfig.limitToSingleInstance == true) { 56 | logger.log(">>> EXECUTION SKIPPED <<<"); 57 | return Promise.resolve(cache.get()); 58 | } 59 | 60 | logger.log(">>> INPUT FOR LINTING <<<") 61 | logger.log(`> filePath = ${filePath}`); 62 | logger.log(`> projectDir = ${projectDir}`); 63 | logger.log(`> cmd = ${cmd}`); 64 | logger.log("> args = []") 65 | logger.log('>>> END <<<'); 66 | 67 | if (!canExecute(cmd)) { 68 | atom.notifications.addError(`Provided path doesn't exist.\n\n${cmd}\n\nPlease fix pylama path or install latest version.`); 69 | return Promise.resolve(cache.get()); 70 | } 71 | 72 | if (this.isForLintOnFly(textEditor)) { 73 | this.tempFile = this.tempFileHandler.create(textEditor.getText()); 74 | let parser = new OnFlyParameterParser(); 75 | let result= parser.parse(projectDir, this.tempFile.path, this.runtimeConfig); 76 | args = result.args; 77 | projectDir = result.projectDir; 78 | } else if (this.isForLintOnSave(textEditor)) { 79 | let parser = new SaveParameterParser(); 80 | let result = parser.parse(projectDir, filePath, this.runtimeConfig); 81 | args = result.args; 82 | projectDir = result.projectDir; 83 | } else { 84 | return Promise.resolve(cache.get()); 85 | } 86 | 87 | logger.log(">>> NEW ARGS <<<"); 88 | logger.log(`> ${args}`); 89 | logger.log('>>> END <<<'); 90 | 91 | return this.runner.run(textEditor, this.runtimeConfig, projectDir, cmd, args, this.running, this.tempFile); 92 | } 93 | 94 | calculateProjectDir(filePath) { 95 | let projectDir = atom.project.relativizePath(filePath)[0] 96 | if (projectDir) { 97 | return projectDir; 98 | } 99 | let fileDir = path.dirname(filePath); 100 | if (fileDir) { 101 | return fileDir; 102 | } 103 | return os.tmpdir(); 104 | } 105 | 106 | isForLintOnFly(textEditor) { 107 | if (this.runtimeConfig.lintOnFly && textEditor.isModified()) { 108 | return true; 109 | } else { 110 | return false; 111 | } 112 | } 113 | 114 | isForLintOnSave(textEditor) { 115 | if (this.runtimeConfig.lintOnSave && !textEditor.isModified()) { 116 | return true; 117 | } else { 118 | return false; 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/logger.ts: -------------------------------------------------------------------------------- 1 | /** Module to log debug prints if debug prints are enabled */ 2 | 3 | export class Logger { 4 | 5 | private static _instance:Logger = new Logger(); 6 | 7 | private _enabled:boolean = false; 8 | 9 | constructor() { 10 | if(Logger._instance){ 11 | throw new Error("Error: Instantiation failed: Use Logger.getInstance() instead of new."); 12 | } 13 | Logger._instance = this; 14 | } 15 | 16 | public static getInstance():Logger 17 | { 18 | return Logger._instance; 19 | } 20 | 21 | public enableLogger() { 22 | if (!this._enabled) { 23 | this._enabled = true; 24 | console.log(">>> DEBUG ENABLED <<<"); 25 | } 26 | } 27 | 28 | public disableLogger() { 29 | if (this._enabled) { 30 | this._enabled = false; 31 | console.log(">>> DEBUG DISABLED <<<"); 32 | } 33 | } 34 | 35 | public log(message) { 36 | if (this._enabled) { 37 | console.log(message); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/parser.ts: -------------------------------------------------------------------------------- 1 | /** Module responsible to read, parse message returned by pylama application. 2 | This module should return also link to github page where all errors 3 | are available.*/ 4 | import { Logger } from './logger'; 5 | import { canRead } from './util'; 6 | 7 | const docUrl = 'https://github.com/pchomik/linter-python-doc/blob/master/errors/' 8 | 9 | const genericRegexp = /(.*):(\d+):(\d+):\s(.\d+)\s*(.*)\[(.*)\]$/; // file:row:col:error:message:tool 10 | const pyflakesRegexp = /(.*):(\d+):(\d+):\s*(.*)\[(.*)\]$/; // file:row:col:message:tool 11 | const logger: Logger = Logger.getInstance(); 12 | const path = require('path'); 13 | const atomLinter = require('atom-linter'); 14 | 15 | 16 | export class MessageParser { 17 | 18 | parseLines(data) { 19 | let results = []; 20 | let lines = data.split(/(\r|\n|\r\n)/).filter(function(line) { return !!line.trim(); }); 21 | for (let line of lines) { 22 | let found = line.match(genericRegexp); 23 | if (found) { 24 | results.push({ 25 | 'fileName': found[1], 26 | 'row': Number(found[2]), 27 | 'col': Number(found[3]), 28 | 'error': found[4], 29 | 'message': found[5], 30 | 'tool': found[6] 31 | }); 32 | } 33 | else { 34 | found = line.match(pyflakesRegexp); 35 | if (found) { 36 | results.push({ 37 | 'fileName': found[1], 38 | 'row': Number(found[2]), 39 | 'col': Number(found[3]), 40 | 'error': '', 41 | 'message': found[4], 42 | 'tool': found[5] 43 | }); 44 | } 45 | } 46 | } 47 | return results; 48 | } 49 | 50 | buildMessage(textEditor, result, config) { 51 | let line = textEditor.getBuffer().lineForRow(result.row - 1); 52 | let filePath = textEditor.getPath(); 53 | let resultType = 'Warning'; 54 | 55 | if (result.error.indexOf('E') > -1 || result.error.indexOf('F') > -1) { 56 | resultType = 'Error'; 57 | } 58 | let text = this.buildErrorText(result, config); 59 | let range = atomLinter.rangeFromLineNumber(textEditor, result.row -1, result.col - 1); 60 | let message = { 61 | type: resultType, 62 | html: text, 63 | filePath: filePath, 64 | range: range, 65 | }; 66 | logger.log(">>> NEW MESSAGE <<"); 67 | logger.log(`> type = ${message.type}`) 68 | logger.log(`> html = ${message.html}`) 69 | logger.log(`> filePath = ${message.filePath}`) 70 | logger.log(`> range = ${message.range}`) 71 | logger.log(">>> END <<<"); 72 | return message; 73 | } 74 | 75 | buildErrorText(result, config) { 76 | if (!result.tool) { 77 | return `${result.error} ${result.message}`; 78 | } 79 | else if(result.tool == 'mccabe') { 80 | return `${result.error} ${result.message} [${result.tool}]`; 81 | } 82 | else { 83 | return `${result.error} ${result.message} [${result.tool}]`; 84 | } 85 | } 86 | } 87 | 88 | 89 | export class SaveParameterParser { 90 | public parse(projectDir, filePath, config) { 91 | return { 92 | 'args': config.pylamaArgs.concat(['--sort', 'E,W,D', '-f', 'pep8', filePath]), 93 | 'projectDir': projectDir 94 | } 95 | } 96 | } 97 | 98 | 99 | export class OnFlyParameterParser { 100 | public parse(projectDir, filePath, config) { 101 | let pylama_options_file = path.join(projectDir, 'pylama.ini'); 102 | projectDir = path.dirname(filePath); 103 | if (canRead(pylama_options_file)) { 104 | return { 105 | 'args': config.pylamaArgs.concat(['--sort', 'E,W,D', '-o', pylama_options_file, '-f', 'pep8', filePath]), 106 | 'projectDir': projectDir 107 | } 108 | } else { 109 | return { 110 | 'args': config.pylamaArgs.concat(['--sort', 'E,W,D', '-f', 'pep8', filePath]), 111 | 'projectDir': projectDir 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/runner.ts: -------------------------------------------------------------------------------- 1 | /** Module to handle process execution. */ 2 | import { Logger } from './logger'; 3 | import { MessageParser } from './parser'; 4 | import { Cache } from './cache'; 5 | 6 | const cp = require('child-process-es6-promise'); 7 | const logger:Logger = Logger.getInstance(); 8 | const cache:Cache = Cache.getInstance(); 9 | 10 | declare var atom; 11 | 12 | /** Class to execute process and return read output. */ 13 | export class ProcessRunner { 14 | 15 | parser: MessageParser; 16 | 17 | constructor() { 18 | this.parser = new MessageParser(); 19 | } 20 | run(textEditor, config, projectDir, cmd, args, runningFlag, tempFile) { 21 | return new Promise((resolve) => { 22 | let messages = [] 23 | cp.spawn(cmd, args, {cwd: projectDir}) 24 | .then((result) => { 25 | // Pylama's exit code is 0 when there are no linting errors. 26 | logger.log(">>> NO ERRORS <<<"); 27 | logger.log(">>> RAW OUTPUT <<<"); 28 | logger.log(result.stdout); 29 | logger.log(">>> END <<<"); 30 | return resolve(messages); 31 | }) 32 | .catch((error) => { 33 | // Pylama's exit code is 1 when there are linting errors. 34 | logger.log(">>> RAW OUTPUT <<<"); 35 | logger.log(error.stdout); 36 | logger.log(">>> END <<<"); 37 | let parsedLines = this.parser.parseLines(error.stdout); 38 | for (let parsedLine of parsedLines) { 39 | let message = this.parser.buildMessage(textEditor, parsedLine, config); 40 | messages.unshift(message); 41 | } 42 | runningFlag = false; 43 | if(tempFile) { 44 | tempFile.clean(); 45 | } 46 | cache.store(messages); 47 | return resolve(messages); 48 | }); 49 | }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from './logger'; 2 | 3 | const temp = require('temp'); 4 | const fs = require('fs'); 5 | const logger:Logger = Logger.getInstance(); 6 | 7 | 8 | export class TempFileHandler { 9 | track: any; 10 | 11 | create(text) { 12 | let tempFile = temp.openSync({suffix: '.py'}); 13 | fs.writeSync(tempFile.fd, text); 14 | fs.closeSync(tempFile.fd); 15 | return new TempFileWrapper(tempFile); 16 | } 17 | } 18 | 19 | 20 | export class TempFileWrapper { 21 | tempFile: any; 22 | path: String; 23 | 24 | constructor(tempFile) { 25 | this.tempFile = tempFile; 26 | this.path = tempFile.path; 27 | } 28 | 29 | clean() { 30 | if (this.tempFile == null) { 31 | return; 32 | } 33 | fs.unlink(this.path); 34 | this.path = null; 35 | this.tempFile = null; 36 | } 37 | 38 | 39 | } 40 | 41 | 42 | export function canExecute(path) { 43 | logger.log(">>> EXECUTE CHECK <<<"); 44 | try { 45 | fs.accessSync(path, fs.R_OK | fs.X_OK); 46 | logger.log("> Path can be executed"); 47 | logger.log(">>> END <<<"); 48 | return true; 49 | } 50 | catch(err) { 51 | logger.log("> Path can not be executed:"); 52 | logger.log(err); 53 | logger.log(">>> END <<<"); 54 | return false; 55 | } 56 | } 57 | 58 | 59 | export function canRead(path) { 60 | logger.log(">>> READ CHECK <<<"); 61 | try { 62 | fs.accessSync(path, fs.R_OK); 63 | logger.log("> Path can be read"); 64 | logger.log(">>> END <<<") 65 | return true; 66 | } 67 | catch(err) { 68 | logger.log("> Path can not be read"); 69 | logger.log(err); 70 | logger.log(">>> END <<<") 71 | return false; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | """Some.""" 2 | from os import path 3 | 4 | 5 | def main(): 6 | """Some docstring.""" 7 | if path.exists('/tmp'): 8 | return True 9 | 10 | 11 | 12 | 13 | if __name__ == '__main__': 14 | main() 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "moduleResolution": "node", 5 | "sourceMap": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "removeComments": false, 9 | "noImplicitAny": false, 10 | "outDir": "./lib" 11 | }, 12 | "exclude": [ 13 | "node_modules", 14 | "typings/main", 15 | "typings/main.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDependencies": { 3 | "core-js": "registry:dt/core-js#0.0.0+20160317120654", 4 | "jasmine": "registry:dt/jasmine#2.2.0+20160505161446", 5 | "node": "registry:dt/node#4.0.0+20160509154515" 6 | } 7 | } 8 | --------------------------------------------------------------------------------