Commit 3da6d2cd authored by Michał Góral's avatar Michał Góral

Enable pylint, flake8, coverage, CI

parent e9f4f17c
Pipeline #56477550 passed with stage
in 2 minutes and 7 seconds
# vim: ft=dosini fileencoding=utf-8:
[run]
branch = True
[report]
exclude_lines =
pragma: no cover
def __repr__
if self\.debug
fail_under = 75
show_missing = True
[flake8]
exclude = _version.py,.git,build,.tox,.eggs
# E501: Line too long
# F401: Unused import
ignore =
E501,
E731,
F401
......@@ -9,6 +9,9 @@ build/
.tox/
.cache/
.coverage
coverage.xml
htmlcov/
src/twc/_version.py
......
image: python:3.5
stages:
- test
before_script:
- pip3 install tox
.test: &test
stage: test
script:
- tox -e $CI_JOB_NAME
py35:
<<: *test
image: python:3.5
py36:
<<: *test
image: python:3.6
py37:
<<: *test
image: python:3.7
pylint:
<<: *test
flake8:
<<: *test
coverage:
<<: *test
artifacts:
name: coverage
expire_in: 14 days
paths:
- coverage.xml
- htmlcov/
allow_failure: true
[MASTER]
ignore=_version.py
[MESSAGES CONTROL]
enable=all
disable=fixme,
too-many-lines,
too-few-public-methods,
too-many-instance-attributes,
unused-argument,
no-self-use,
global-statement,
bare-except,
missing-docstring,
[BASIC]
attr-rgx=[a-z_][a-z0-9_]{0,30}$
argument-rgx=[a-z_][a-z0-9_]{0,30}$
const-rgx=[A-Za-z_][A-Za-z0-9_]{0,30}$
variable-rgx=[a-z_][a-z0-9_]{0,30}$
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{1,30}|(__.*__))$
no-docstring-rgx=(^_|^main$|^test_)
[FORMAT]
expected-line-ending-format=LF
ignore-long-lines=(<?https?://|# (pylint|flake8): disable=)
[DESIGN]
max-args=10
# vim: ft=dosini fileencoding=utf-8:
......@@ -45,5 +45,6 @@ def main():
},
)
if __name__ == '__main__':
main()
import sys
# Copyright (C) 2019 Michał Góral.
#
# This file is part of TWC
#
# TWC is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# TWC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with TWC. If not, see <http://www.gnu.org/licenses/>.
'''TWC entry point'''
import argparse
import urwid
import taskw
......@@ -33,7 +51,8 @@ def parse_args():
def run():
args = parse_args()
'''Runs application'''
parse_args()
cfg = config.config()
tw = taskw.TaskWarrior()
......
......@@ -17,15 +17,13 @@
'''Reader and handler of globally-available app configuration.'''
import os
import attr
from collections import OrderedDict
import attr
import mgcomm.xdg
import mgcomm.env
from twc.locale import _
@attr.s
class Block:
......@@ -87,7 +85,7 @@ class Config:
# pre-compute default focus for all default markups
default_focus = ('standout', '')
focus = [ ('{}-focus'.format(c), default_focus) for c in colors ]
focus = [('{}-focus'.format(c), default_focus) for c in colors]
colors.update(focus)
return colors
......@@ -100,17 +98,19 @@ class Config:
def _create_default_blocks(cfg):
cfg.add_block('default',
cfg.add_block(
'default',
name='Next tasks',
filter='status:pending',
fmt = '<m class=comment>{id: >4}</m> <m class=warning>{priority:<2}</m>{description} <m class=info>{tags:>}</m>',
fmt='<m class=comment>{id: >4}</m> <m class=warning>{priority:<2}</m>{description} <m class=info>{tags:>}</m>', # pylint: disable=line-too-long
sort='priority-,id+',
height='70%')
cfg.add_block('default',
cfg.add_block(
'default',
name='Recently completed',
filter='status:completed limit:10',
fmt = '{description}',
fmt='{description}',
sort='id+',
height='12')
......@@ -123,13 +123,6 @@ def config_path():
This function doesn't ensure that configuration file indeed exists. If no
suitable configuration exists, it returns a user-specific path which is best
suitable (according to XDG spec).'''
app_name = 'twc'
cfg_name = 'config.ini'
default_cfg_dir = os.path.join(mgcomm.env.home(), '.config')
cfg_home = os.getenv('XDG_CONFIG_HOME', default_cfg_dir)
default_path = os.path.join(cfg_home, app_name, cfg_name)
return mgcomm.xdg.basedir('config', subdir='twc', file='config.py')
......@@ -141,7 +134,7 @@ def config():
try:
with open(filename) as cfg_mod:
code = compile(cfg_mod.read(), filename, 'exec')
exec(code, {'c': cfg})
exec(code, {'c': cfg}) # pylint: disable=exec-used
except FileNotFoundError:
pass
......
......@@ -31,4 +31,3 @@ t = gettext.translation(
_ = t.gettext
P_ = t.ngettext
......@@ -18,17 +18,19 @@
from html.parser import HTMLParser
import attr
# pylint: disable=abstract-method
@attr.s
class Parser(HTMLParser):
'''Parser of task format markup'''
markup = attr.ib(factory=list)
_curr = attr.ib(None)
def __attrs_post_init__(self):
super().__init__()
def handle_starttag(self, tag, tag_attrs):
def handle_starttag(self, tag, attrs):
if tag == 'm':
self._curr = self._find_attr('class', tag_attrs)
self._curr = self._find_attr('class', attrs)
def handle_endtag(self, tag):
if tag == 'm':
......
......@@ -48,4 +48,3 @@ def _register_pentry(screen, name, fg, bg):
screen.register_palette_entry(name, fg, bg)
except urwid.display_common.AttrSpecError:
screen.register_palette_entry(name, '', '', None, fg, bg)
......@@ -19,7 +19,8 @@
import shlex
def process_filter(f):
def _process_filter(f):
if not f:
return []
# TODO: search for limit:<l>. It should be extracted and applied after sort.
......@@ -32,5 +33,6 @@ def process_filter(f):
def filter_tasks(filter_string, tw):
query = process_filter(filter_string)
return tw._get_task_objects(*query, 'export')
'''Returns a list of tasks filtered by a given TW-compatible string'''
query = _process_filter(filter_string)
return tw._get_task_objects(*query, 'export') # pylint: disable=protected-access
......@@ -17,7 +17,9 @@
'''Utility functions'''
import sys
def eprint(*args, **kwargs):
'''Print to stderr.'''
print(*args, file=sys.stderr, **kwargs)
......@@ -15,16 +15,16 @@
# You should have received a copy of the GNU General Public License
# along with TWC. If not, see <http://www.gnu.org/licenses/>.
import re
import urwid
import taskw
import attr
'''Widgets used by TWC'''
from collections import defaultdict
import urwid
import twc.markup as markup
import twc.twutils as twutils
def _dim(dimstr, realdim):
if dimstr.endswith('%'):
dimstr = int(dimstr[:-1])
......@@ -32,11 +32,11 @@ def _dim(dimstr, realdim):
return int(dimstr)
class Task(urwid.Text):
class TaskView(urwid.Text):
'''View of a single task'''
_selectable = True
def __init__(self, screen, data, fmt):
# TODO: how can term be used? (mgl, 2019-04-11)
def __init__(self, data, fmt):
data['tags'] = ':'.join(data.setdefault('tags', []))
# defaultdict handles optional attributes, which are specified
......@@ -54,19 +54,19 @@ class Task(urwid.Text):
class BlockView(urwid.BoxAdapter):
'''View of a single agenda block, i.e. a list of tasks'''
def __init__(self, screen, cfg, tw, block):
self.block = block
self.tasks = twutils.filter_tasks(block.filter, tw)
focus_map = { c : '{}-focus'.format(c)
for c in cfg.colors if not c.endswith('-focus') }
focus_map = {c: '{}-focus'.format(c)
for c in cfg.colors if not c.endswith('-focus')}
focus_map[None] = 'text-focus'
textboxes = [urwid.AttrMap(Task(screen, t, self.block.fmt),
textboxes = [urwid.AttrMap(TaskView(t, self.block.fmt),
None, focus_map)
for t in self.tasks]
lw = urwid.ListBox(urwid.SimpleFocusListWalker(textboxes))
lb = urwid.LineBox(lw, title=self.block.name)
height = _dim(self.block.height, screen.get_cols_rows()[1])
......@@ -74,6 +74,8 @@ class BlockView(urwid.BoxAdapter):
class AgendaView(urwid.ListBox):
'''Agenda view, i.e. a single string which contains many blocks (lists) of
differently filtered and presented tasks.'''
def __init__(self, screen, cfg, tw, agenda):
blocks = [BlockView(screen, cfg, tw, block) for block in agenda.blocks]
super().__init__(blocks)
......
......@@ -7,12 +7,12 @@ import twc.markup as markup
@pytest.mark.parametrize('fmt,expected', [
('', []),
('foo bar', ['foo bar']),
('foo <m class=highlight>bar baz</m> blah',
('foo <m class=highlight>bar baz</m> blah',
['foo ', ('highlight', 'bar baz'), ' blah']),
('foo <m class="highlight">bar baz</m> blah',
('foo <m class="highlight">bar baz</m> blah',
['foo ', ('highlight', 'bar baz'), ' blah']),
])
def test_markup(fmt,expected):
def test_markup(fmt, expected):
p = markup.Parser()
p.feed(fmt)
assert p.markup == expected
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment