diff --git a/tests/samples/output/test_help_contents b/tests/samples/output/test_help_contents index 35aa35f..4728c76 100644 --- a/tests/samples/output/test_help_contents +++ b/tests/samples/output/test_help_contents @@ -36,8 +36,8 @@ optional arguments: optional alternate project name; auto-discovered project takes priority --alternate-language ALTERNATE_LANGUAGE - optional alternate language name; auto-detected - languagetakes priority + optional alternate language name; if valid, takes + priority over auto-detected language --hostname HOSTNAME hostname of current machine. --disableoffline disables offline time logging instead of queuing logged time diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index d5a560c..d85b72c 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -836,3 +836,67 @@ class DependenciesTestCase(utils.TestCase): self.assertListsEqual(dependencies, expected_dependencies) self.assertEquals(stats, json.loads(self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][1])) self.patched['wakatime.offlinequeue.Queue.pop'].assert_not_called() + + def test_dependencies_still_detected_when_alternate_language_used(self): + response = Response() + response.status_code = 0 + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + + with utils.TemporaryDirectory() as tempdir: + entity = 'tests/samples/codefiles/python.py' + shutil.copy(entity, os.path.join(tempdir, 'python.py')) + entity = os.path.realpath(os.path.join(tempdir, 'python.py')) + + now = u(int(time.time())) + config = 'tests/samples/configs/good_config.cfg' + + args = ['--file', entity, '--config', config, '--time', now, '--alternate-language', 'PYTHON'] + + with utils.mock.patch('wakatime.stats.smart_guess_lexer') as mock_guess_lexer: + mock_guess_lexer.return_value = None + + retval = execute(args) + + self.assertEquals(retval, 102) + self.assertEquals(sys.stdout.getvalue(), '') + self.assertEquals(sys.stderr.getvalue(), '') + + self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with() + self.patched['wakatime.session_cache.SessionCache.delete'].assert_called_once_with() + self.patched['wakatime.session_cache.SessionCache.save'].assert_not_called() + + heartbeat = { + 'language': u('Python'), + 'lines': 37, + 'entity': os.path.realpath(entity), + 'project': u(os.path.basename(os.path.realpath('.'))), + 'dependencies': ANY, + 'time': float(now), + 'type': 'file', + } + stats = { + u('cursorpos'): None, + u('dependencies'): ANY, + u('language'): u('Python'), + u('lineno'): None, + u('lines'): 37, + } + expected_dependencies = [ + 'app', + 'django', + 'flask', + 'jinja', + 'mock', + 'pygments', + 'simplejson', + 'sqlalchemy', + 'unittest', + ] + + self.patched['wakatime.offlinequeue.Queue.push'].assert_called_once_with(ANY, ANY, None) + for key, val in self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0].items(): + self.assertEquals(heartbeat[key], val) + dependencies = self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0]['dependencies'] + self.assertListsEqual(dependencies, expected_dependencies) + self.assertEquals(stats, json.loads(self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][1])) + self.patched['wakatime.offlinequeue.Queue.pop'].assert_not_called() diff --git a/tests/test_languages.py b/tests/test_languages.py index 5fe1d3e..f9b50ee 100644 --- a/tests/test_languages.py +++ b/tests/test_languages.py @@ -104,7 +104,7 @@ class LanguagesTestCase(utils.TestCase): language = u('Python') self.assertEqual(self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0].get('language'), language) - def test_alternate_language_not_used_when_guessed(self): + def test_alternate_language_takes_priority_over_detected_language(self): response = Response() response.status_code = 500 self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response @@ -112,12 +112,12 @@ class LanguagesTestCase(utils.TestCase): now = u(int(time.time())) config = 'tests/samples/configs/good_config.cfg' entity = 'tests/samples/codefiles/python.py' - args = ['--file', entity, '--config', config, '--time', now, '--alternate-language', 'java'] + args = ['--file', entity, '--config', config, '--time', now, '--alternate-language', 'JAVA'] retval = execute(args) self.assertEquals(retval, 102) - language = u('Python') + language = u('Java') self.assertEqual(self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0].get('language'), language) def test_alternate_language_is_used_when_not_guessed(self): diff --git a/wakatime/arguments.py b/wakatime/arguments.py index 988987b..e0b1e5b 100644 --- a/wakatime/arguments.py +++ b/wakatime/arguments.py @@ -82,8 +82,8 @@ def parseArguments(): help='optional alternate project name; auto-discovered project '+ 'takes priority') parser.add_argument('--alternate-language', dest='alternate_language', - help='optional alternate language name; auto-detected language'+ - 'takes priority') + help='optional alternate language name; if valid, takes priority '+ + 'over auto-detected language') parser.add_argument('--hostname', dest='hostname', help='hostname of '+ 'current machine.') parser.add_argument('--disableoffline', dest='offline', diff --git a/wakatime/stats.py b/wakatime/stats.py index 1fa8df7..5c0a28d 100644 --- a/wakatime/stats.py +++ b/wakatime/stats.py @@ -18,6 +18,7 @@ from .dependencies import DependencyParser from .packages.pygments.lexers import ( ClassNotFound, + find_lexer_class, get_lexer_by_name, guess_lexer_for_filename, ) @@ -43,11 +44,15 @@ def get_file_stats(file_name, entity_type='file', lineno=None, cursorpos=None, 'cursorpos': cursorpos, } else: - language, lexer = guess_language(file_name) + language = standardize_language(alternate_language, plugin) + lexer = get_lexer(language) + + if not language: + language, lexer = guess_language(file_name) + parser = DependencyParser(file_name, lexer) dependencies = parser.parse() - if language is None and alternate_language: - language = standardize_language(alternate_language, plugin) + stats = { 'language': language, 'dependencies': dependencies, @@ -58,6 +63,19 @@ def get_file_stats(file_name, entity_type='file', lineno=None, cursorpos=None, return stats +def get_lexer(language): + """Return a Pygments Lexer object for the given language string.""" + + if not language: + return None + + lexer_cls = find_lexer_class(language) + if lexer_cls: + return lexer_cls() + + return None + + def guess_language(file_name): """Guess lexer and language for a file. @@ -188,6 +206,9 @@ def number_lines_in_file(file_name): def standardize_language(language, plugin): """Maps a string to the equivalent Pygments language.""" + if not language: + return None + # standardize language for this plugin if plugin: plugin = plugin.split(' ')[-1].split('/')[0].split('-')[0]