Skip to content

Commit

Permalink
Directory restructure for PyPI readiness (#1)
Browse files Browse the repository at this point in the history
* Directory restructure for PyPI readiness

Add meta files for PyPI readiness.
Move projects into `src/` to model after PyPA sample project.
Move script to `src/stylist/__main__.py`.
Add basic Github action to run linter and test.

* Happiness for flake8 and pytest

Remove Python 2 compat.
Minor syntax update to satisfy flake8 and pytest.

* Test all supported versions

Also include coverage.

* Fix pytest coverage syntax

Use package name instead of src.
Fail if coverage less than 75%.

* Remove unnecessary __main__ test

Already in __main__.py module!

* Update description for package

* src -> source

This is preferred by the reviewer.
  • Loading branch information
matthewrmshin authored and MatthewHambley committed Dec 17, 2019
1 parent b6815a6 commit 940ba3e
Show file tree
Hide file tree
Showing 16 changed files with 124 additions and 48 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Python package

on: [push]

jobs:
build:

runs-on: ubuntu-latest
strategy:
max-parallel: 3
matrix:
python-version: [3.6, 3.7, 3.8]

steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install
run: |
python3 -m pip install --upgrade pip
pip install -e .
- name: Lint with flake8
run: |
pip install -e .[dev]
flake8 . --count --show-source --statistics
- name: Test with pytest
run: |
pip install .[test]
pytest --cov stylist --cov-fail-under=75
8 changes: 8 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Include the README
include *.md

# Include the license file
include LICENSE

# Include the documentation files
recursive-include documentation *
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[metadata]
license_files = LICENSE
53 changes: 53 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""Setup Stylist for distribution on PyPI."""

import os
from setuptools import setup, find_packages

# Get the long description from the README file
with open(
os.path.join(os.path.dirname(__file__), 'README.md'),
encoding='utf-8',
) as handle:
LONG_DESCRIPTION = handle.read()

setup(
name='stylist',
# TODO:
# For a discussion on single-sourcing the version across setup.py and the
# project code, see
# https://packaging.python.org/en/latest/single_source_version.html
version='0.1',
description=(
'Extensible code style checker'
' currently supporting Fortran, PSyclone DSL, etc'
),
long_description=LONG_DESCRIPTION,
long_description_content_type='text/markdown',
url='https://github.com/MetOffice/stylist',
author='Met Office',
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'Topic :: Software Development :: Quality Assurance',
'License :: OSI Approved :: BSD License',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],
keywords='linter fortran psyclone',
package_dir={'': 'source'},
packages=find_packages(where='source'),
python_requires='>=3.6, <4',
install_requires=['fparser'],
extras_require={
'dev': ['check-manifest', 'flake8'],
'test': ['pytest', 'pytest-cov'],
},
entry_points={
'console_scripts': ['stylist=stylist.__main__:main'],
},
project_urls={
'Bug Reports': 'https://github.com/MetOffice/stylist/issues',
'Source': 'https://github.com/MetOffice/stylist/',
},
)
File renamed without changes.
11 changes: 5 additions & 6 deletions bin/stylist → source/stylist/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
Tool for checking code style.
'''

from __future__ import absolute_import, division, print_function

import argparse
import logging
import os.path
Expand All @@ -22,7 +20,7 @@
from stylist.style import LFRicStyle


def cli():
def parse_cli():
'''
Parse the command line. Returns a dictionary of arguments.
'''
Expand Down Expand Up @@ -82,7 +80,7 @@ def _add_extensions(additional_extensions):
*preproc_objects)


def main(arguments):
def process(arguments):
'''
Examines files for style compliance.
Expand Down Expand Up @@ -126,5 +124,6 @@ def main(arguments):
sys.exit(1)


if __name__ == '__main__':
main(cli())
def main():
'''Main entry point.'''
return process(parse_cli())
2 changes: 0 additions & 2 deletions lib-python/stylist/engine.py → source/stylist/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
'''
Core of the Fortran style checking tool.
'''
from __future__ import absolute_import, division, print_function

import logging

import stylist.source
Expand Down
1 change: 0 additions & 1 deletion lib-python/stylist/issue.py → source/stylist/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
'''
Issues found in the source.
'''
from __future__ import absolute_import, division, print_function


class Issue(object):
Expand Down
12 changes: 5 additions & 7 deletions lib-python/stylist/rule.py → source/stylist/rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,18 @@
'''
A collection of style rules.
'''
from __future__ import absolute_import, division, print_function

from abc import ABCMeta, abstractmethod
import logging
import re
from six import add_metaclass

import fparser.two.Fortran2003
import fparser.common.readfortran
from stylist.issue import Issue
from stylist.source import FortranSource


@add_metaclass(ABCMeta)
class Rule(object):
class Rule(object, metaclass=ABCMeta):
# pylint: disable=too-few-public-methods
'''
Abstract parent of all rules.
Expand Down Expand Up @@ -113,7 +110,9 @@ class TrailingWhitespace(Rule):

def examine(self, subject):
'''
Examines the text for white space at the end of lines. This includes empty lines.
Examines the text for white space at the end of lines.
This includes empty lines.
:param subject: File contents as Source object.
:return: List of issues or empty list.
'''
Expand All @@ -131,8 +130,7 @@ def examine(self, subject):
return issues


@add_metaclass(ABCMeta)
class FortranRule(Rule):
class FortranRule(Rule, metaclass=ABCMeta):
'''
Parent for style rules pertaining to Fortran source.
'''
Expand Down
11 changes: 3 additions & 8 deletions lib-python/stylist/source.py → source/stylist/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,18 @@
'''
Manages source code in various flavours.
'''
from __future__ import absolute_import, division, print_function

from abc import ABCMeta, abstractmethod
import re
import os.path
from six import add_metaclass

import fparser.common.readfortran as readfortran
import fparser.two.Fortran2003
from fparser.two.parser import ParserFactory
from fparser.two.utils import FparserException


@add_metaclass(ABCMeta)
class SourceText(object):
class SourceText(object, metaclass=ABCMeta):
# pylint: disable=too-few-public-methods
'''
Handles source code at the text level. Makes use of the decorator pattern
Expand Down Expand Up @@ -70,8 +67,7 @@ def get_text(self):
return self._source_string


@add_metaclass(ABCMeta)
class TextProcessor(SourceText):
class TextProcessor(SourceText, metaclass=ABCMeta):
# pylint: disable=too-few-public-methods, abstract-method
'''
Preprocessor decorators inherit from this.
Expand Down Expand Up @@ -148,8 +144,7 @@ def get_text(self):
return text


@add_metaclass(ABCMeta)
class SourceTree(object):
class SourceTree(object, metaclass=ABCMeta):
'''
Abstract parent of all actual language source files.
'''
Expand Down
1 change: 0 additions & 1 deletion lib-python/stylist/style.py → source/stylist/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
'''
Classes relating to styles made up of rules.
'''
from __future__ import absolute_import, division, print_function

from abc import ABCMeta
import logging
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
'''
Ensures the 'engine' module functions as expected.
'''
from __future__ import absolute_import, division, print_function

import tempfile

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
'''
Ensures the Issue object functions as expected.
'''
from __future__ import absolute_import, division, print_function

import stylist.issue

Expand Down
26 changes: 14 additions & 12 deletions lib-python/stylist/tests/rule_test.py → tests/rule_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
'''
Tests of the stylist.rule module.
'''
from __future__ import absolute_import, division, print_function

import fparser.two.Fortran2003
import stylist.rule
Expand Down Expand Up @@ -121,7 +120,7 @@ def test_simple(self, simple_source):
write( output_unit, '("Hello ", A)' ) 'world'
end program some_trailing_whitespace
'''
''' # noqa: W291, W293

_PF_TWS = '''module trailing_whitespace_in_unit_tests
Expand All @@ -146,7 +145,8 @@ def test_simple(self, simple_source):
end subroutine test_thing
end module trailing_whitespace_in_unit_tests'''
end module trailing_whitespace_in_unit_tests''' # noqa: W291, W293


class TestTrailingWhitespace(object):
'''
Expand All @@ -172,9 +172,11 @@ def test_examples(self, example_source):
reader = SourceStringReader(example_source[0])
source = FortranSource(reader)
issues = unit_under_test.examine(source)
assert [str(issue) for issue in issues] \
== [str(eln) + ': Found trailing white space'
for eln in example_source[1]]
assert (
[str(issue) for issue in issues]
== [str(eln) + ': Found trailing white space'
for eln in example_source[1]]
)


class TestMissingImplicit(object):
Expand Down Expand Up @@ -392,7 +394,7 @@ def unit_type(self, request):
'''
Parameter fixture giving program unit types.
'''
#pylint: disable=no-self-use
# pylint: disable=no-self-use
yield request.param

@pytest.fixture(scope='class',
Expand All @@ -409,8 +411,8 @@ def ignorance(self, request):
[('missing_mod', [])],
[('present_mod', ['stuff'])],
[('multi_mod', ['one', 'two'])],
[('missing_mod', []),('present_mod', ['stuff'])],
[('present_mod', ['stuff']),('missing_mod',[])]])
[('missing_mod', []), ('present_mod', ['stuff'])],
[('present_mod', ['stuff']), ('missing_mod', [])]])
def unit_usage(self, request):
'''
Parameter fixture giving permutations of "use" statements.
Expand All @@ -423,8 +425,8 @@ def unit_usage(self, request):
[('missing_mod', [])],
[('present_mod', ['stuff'])],
[('multi_mod', ['one', 'two'])],
[('missing_mod', []),('present_mod', ['stuff'])],
[('present_mod', ['stuff']),('missing_mod',[])]])
[('missing_mod', []), ('present_mod', ['stuff'])],
[('present_mod', ['stuff']), ('missing_mod', [])]])
def procedure_usage(self, request):
'''
Parameter fixture giving permutations of "use" statements.
Expand All @@ -437,7 +439,7 @@ def test_use(self, unit_type, unit_usage, procedure_usage, ignorance):
Checks that the rule reports missing "use" clauses correctly.
'''
# pylint: disable=no-self-use
def prepare( params ):
def prepare(params):
usage = []
expectations = []
for details in params:
Expand Down
11 changes: 3 additions & 8 deletions lib-python/stylist/tests/source_test.py → tests/source_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@
'''
Checks source code management classes.
'''
from __future__ import absolute_import, division, print_function

import os.path
import shutil
import tempfile

import fparser.two.Fortran2003
import pytest
Expand Down Expand Up @@ -258,10 +253,10 @@ def test_find_all(self):
unit_under_test = FortranSource(reader)
wanted = fparser.two.Fortran2003.Module_Subprogram
result = unit_under_test.find_all(wanted)
assert str(result.next().content[0].items[1]) == 'one'
assert str(result.next().content[0].items[1]) == 'two'
assert str(next(result).content[0].items[1]) == 'one'
assert str(next(result).content[0].items[1]) == 'two'
with pytest.raises(StopIteration):
result.next()
next(result)


class TestCSource(object):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
'''
Ensures the 'style' module functions as expected.
'''
from __future__ import absolute_import, division, print_function

import stylist.rule
from stylist.source import FortranSource, SourceStringReader
Expand Down

0 comments on commit 940ba3e

Please sign in to comment.