Skip to content

Commit

Permalink
Merge 317e523 into a372917
Browse files Browse the repository at this point in the history
  • Loading branch information
tdenewiler committed Mar 18, 2020
2 parents a372917 + 317e523 commit 5685c98
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 52 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -15,6 +15,7 @@ Pipfile*

# From tests
.coverage
.mypy_cache
.pytest_cache
.tox
output-*/
16 changes: 8 additions & 8 deletions .travis.yml
Expand Up @@ -2,7 +2,6 @@ dist: xenial
sudo: required
language: python
python:
- '3.5'
- '3.6'
- '3.7'
- '3.8'
Expand All @@ -21,6 +20,8 @@ before_install:
install:
- cat install.txt | xargs sudo apt-get install -y
- pip install -r requirements.txt
- pip3 install -r requirements.txt
- pip3 install mypy

# This stage is run against everything in the matrix (so every python version)
script:
Expand All @@ -32,14 +33,13 @@ jobs:
include:
# This adds a second parallel "test" stage (since we didn't specify
# the stage name) just to run statick
- stage: test
python: '3.5'
install:
- cat install.txt | xargs sudo apt-get install -y
- pip install -r requirements.txt
script: statick . --profile self_check.yaml
- stage: self_check
python: '3.8'
script:
- statick . --profile self_check.yaml
- mypy --ignore-missing-imports src/
- stage: deploy
python: '3.5'
python: '3.8'
provider: pypi
user: tdenewiler
password:
Expand Down
14 changes: 14 additions & 0 deletions README.md
Expand Up @@ -9,6 +9,7 @@

![Python Versions](https://img.shields.io/pypi/pyversions/statick-tex.svg)
![License](https://img.shields.io/pypi/l/statick-tex.svg)
[![Checked with mypy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)
![Daily Downloads](https://img.shields.io/pypi/dd/statick-tex.svg)
![Weekly Downloads](https://img.shields.io/pypi/dw/statick-tex.svg)
![Monthly Downloads](https://img.shields.io/pypi/dm/statick-tex.svg)
Expand Down Expand Up @@ -87,3 +88,16 @@ In particular, it is much easier to test whether a bug is fixed (and identify fu
unit test which replicates the bug.

Before submitting a change, please run tox to check that you have not introduced any regressions or violated any code style guidelines.

### Mypy

Statick uses [mypy](http://mypy-lang.org/) to check that type hints are being followed properly.
Type hints are described in [PEP 484](https://www.python.org/dev/peps/pep-0484/) and allow for static typing in Python.
To determine if proper types are being used in Statick plugins the following command will show any errors, and create several
types of reports that can be viewed with a text editor or web browser.

pip install mypy
mkdir report
mypy --ignore-missing-imports --html-report report/ --txt-report report src/

It is hoped that in the future we will generate coverage reports from mypy and use those to check for regressions.
18 changes: 10 additions & 8 deletions src/statick_tex/plugins/discovery/tex_discovery_plugin.py
Expand Up @@ -6,28 +6,30 @@
import os
import subprocess
from collections import OrderedDict
from typing import List

from statick_tool.discovery_plugin import DiscoveryPlugin
from statick_tool.exceptions import Exceptions
from statick_tool.package import Package


class TexDiscoveryPlugin(DiscoveryPlugin):
"""Discover TeX files to analyze."""

def get_name(self):
def get_name(self) -> str:
"""Get name of discovery type."""
return "tex"

def scan(self, package, level, exceptions=None): # pylint: disable=too-many-locals
def scan(self, package: Package, level: str, exceptions: Exceptions = None): # pylint: disable=too-many-locals
"""Scan package looking for TeX files."""
tex_files = []
globs = ["*.tex", "*.bib"]
tex_files: List[str] = []
globs: List[str] = ["*.tex", "*.bib"]

file_cmd_exists = True
file_cmd_exists: bool = True
if not DiscoveryPlugin.file_command_exists():
file_cmd_exists = False

root = ''
files = []
root: str = ''
for root, _, files in os.walk(package.path):
for glob in globs:
for f in fnmatch.filter(files, glob):
Expand All @@ -53,7 +55,7 @@ def scan(self, package, level, exceptions=None): # pylint: disable=too-many-loc

print(" {} TeX files found.".format(len(tex_files)))
if exceptions:
original_file_count = len(tex_files)
original_file_count: int = len(tex_files)
tex_files = exceptions.filter_file_exceptions_early(package,
tex_files)
if original_file_count > len(tex_files):
Expand Down
38 changes: 20 additions & 18 deletions src/statick_tex/plugins/tool/chktex_tool_plugin.py
Expand Up @@ -8,29 +8,31 @@

import re
import subprocess
from typing import List, Match, Optional, Pattern

from statick_tool.issue import Issue
from statick_tool.package import Package
from statick_tool.tool_plugin import ToolPlugin


class ChktexToolPlugin(ToolPlugin):
"""Apply chktex tool and gather results."""

def get_name(self):
def get_name(self) -> str:
"""Get name of tool."""
return "chktex"

def scan(self, package, level):
def scan(self, package: Package, level: str) -> Optional[List[Issue]]:
"""Run tool and gather output."""
flags = []
user_flags = self.get_user_flags(level)
flags: List[str] = []
user_flags: List[str] = self.get_user_flags(level)
flags += user_flags
total_output = []
total_output: List[str] = []

tool_bin = "chktex"
tool_bin: str = "chktex"
for src in package["tex"]:
try:
subproc_args = [tool_bin, src] + flags
subproc_args: List[str] = [tool_bin, src] + flags
output = subprocess.check_output(subproc_args,
stderr=subprocess.STDOUT,
universal_newlines=True)
Expand All @@ -47,7 +49,7 @@ def scan(self, package, level):
print("Couldn't find {}! ({})".format(tool_bin, ex))
return None

if self.plugin_context.args.show_tool_output:
if self.plugin_context and self.plugin_context.args.show_tool_output:
print("{}".format(output))

total_output.append(output)
Expand All @@ -56,22 +58,22 @@ def scan(self, package, level):
for output in total_output:
fname.write(output)

issues = self.parse_output(total_output)
issues: List[Issue] = self.parse_output(total_output)
return issues

def parse_output(self, total_output):
def parse_output(self, total_output: List[str]) -> List[Issue]:
"""Parse tool output and report issues."""
tool_re = r"(.+)\s(\d+)\s(.+)\s(.+)\s(.+)\s(\d+):\s(.+)"
parse = re.compile(tool_re)
issues = []
filename = ''
line_number = 0
issue_type = ''
message = ''
tool_re: str = r"(.+)\s(\d+)\s(.+)\s(.+)\s(.+)\s(\d+):\s(.+)"
parse: Pattern[str] = re.compile(tool_re)
issues: List[Issue] = []
filename: str = ''
line_number: str = "0"
issue_type: str = ''
message: str = ''

for output in total_output:
for line in output.splitlines():
match = parse.match(line)
match: Optional[Match[str]] = parse.match(line)
if match:
if match.group(1) == "Warning":
filename = match.group(4)
Expand Down
38 changes: 20 additions & 18 deletions src/statick_tex/plugins/tool/lacheck_tool_plugin.py
Expand Up @@ -4,29 +4,31 @@

import re
import subprocess
from typing import List, Match, Optional, Pattern

from statick_tool.issue import Issue
from statick_tool.package import Package
from statick_tool.tool_plugin import ToolPlugin


class LacheckToolPlugin(ToolPlugin):
"""Apply lacheck tool and gather results."""

def get_name(self):
def get_name(self) -> str:
"""Get name of tool."""
return "lacheck"

def scan(self, package, level):
def scan(self, package: Package, level: str) -> Optional[List[Issue]]:
"""Run tool and gather output."""
flags = []
user_flags = self.get_user_flags(level)
flags: List[str] = []
user_flags: List[str] = self.get_user_flags(level)
flags += user_flags
total_output = []
total_output: List[str] = []

tool_bin = "lacheck"
tool_bin: str = "lacheck"
for src in package["tex"]:
try:
subproc_args = [tool_bin, src] + flags
subproc_args: List[str] = [tool_bin, src] + flags
output = subprocess.check_output(subproc_args,
stderr=subprocess.STDOUT,
universal_newlines=True)
Expand All @@ -43,7 +45,7 @@ def scan(self, package, level):
print("Couldn't find {}! ({})".format(tool_bin, ex))
return None

if self.plugin_context.args.show_tool_output:
if self.plugin_context and self.plugin_context.args.show_tool_output:
print("{}".format(output))

total_output.append(output)
Expand All @@ -52,22 +54,22 @@ def scan(self, package, level):
for output in total_output:
fname.write(output)

issues = self.parse_output(total_output)
issues: List[Issue] = self.parse_output(total_output)
return issues

def parse_output(self, total_output):
def parse_output(self, total_output: List[str]) -> List[Issue]:
"""Parse tool output and report issues."""
tool_re = r"(.+)\s(.+)\s(\d+):\s(.+)"
parse = re.compile(tool_re)
issues = []
filename = ''
line_number = 0
issue_type = ''
message = ''
tool_re: str = r"(.+)\s(.+)\s(\d+):\s(.+)"
parse: Pattern[str] = re.compile(tool_re)
issues: List[Issue] = []
filename: str = ''
line_number: str = "0"
issue_type: str = ''
message: str = ''

for output in total_output:
for line in output.splitlines():
match = parse.match(line)
match: Optional[Match[str]] = parse.match(line)
if match:
filename = match.group(1)[1:-2]
issue_type = "lacheck"
Expand Down

0 comments on commit 5685c98

Please sign in to comment.