diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edc70e4..6a0a07a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,10 +22,22 @@ jobs: shell: bash run: | pip3 install numpy \ - pytest + pytest \ + build - name: Test shell: bash run: | pytest -v . - \ No newline at end of file + + - name: build + run: python -m build . + + - name: install + shell: bash + run: | + pip install dist/*.whl + do_thing -h + + + diff --git a/acme_corp/__init__.py b/acme_corp/__init__.py new file mode 100644 index 0000000..6758cf7 --- /dev/null +++ b/acme_corp/__init__.py @@ -0,0 +1,2 @@ +# make piano a top-level class +from .piano import Piano diff --git a/acme_corp/__main__.py b/acme_corp/__main__.py new file mode 100644 index 0000000..de2e579 --- /dev/null +++ b/acme_corp/__main__.py @@ -0,0 +1,19 @@ +from . import Piano + +""" +This is a special file that makes this package executable. + +It will only be run when this package is run from the command line, i.e., + +``python -m acme_corp`` +""" + + +def set_trap(): + piano = Piano() + piano.lift() + return piano + + +if __name__ == "__main__": + trap = set_trap() diff --git a/do_task.py b/acme_corp/do_task.py similarity index 67% rename from do_task.py rename to acme_corp/do_task.py index e572987..5952f64 100644 --- a/do_task.py +++ b/acme_corp/do_task.py @@ -4,6 +4,7 @@ logger = logging.getLogger(__name__) +# using Sphinx docstrings style: def perform_action(args, input_data): """Perform some action @@ -11,15 +12,12 @@ def perform_action(args, input_data): Following the principle of separation of concerns, this method only performs the action, but does not have any input or output. - inputs - ------ - args : argparse object with many possible members based on argparse configuration - input_data : dictionary of input data read from YAML file - - outputs - -------- - string that describes the input quantities - + :param args: argparse object with many possible members based on argparse configuration + :type args: argparse.ArgumentParser + :param input_data: dictionary of input data read from YAML file + :type input_data: dict + :returns: string that describes the input quantities + :rtype: str """ return f"Some results based on args:\n{args}\n and input_data:\n{input_data}\n" @@ -31,16 +29,12 @@ def report_results(args, input_data, results): Following the principle of separation of concerns, this method only performs output and does not do any actions. - inputs - ------ - args : argparse object with many possible members based on argparse configuration - input_data : dictionary of input data read from YAML file - results : the results of the action - - outputs - -------- - None + :param args: argparse object with many possible members based on argparse configuration + :type args: argparse.ArgumentParser + :param input_data: dictionary of input data read from YAML file + :type input_data: dict + :returns: None """ logger.info( @@ -56,13 +50,8 @@ def task_args(): `filename` : required positional argument `verbose` : optional keyword argument - inputs - ------- - None - - outputs - -------- - argparse object with various members depending on configuration + :returns: argparse object with various members depending on configuration + :rtype: argparse.ArgumentParser """ parser = argparse.ArgumentParser( @@ -86,7 +75,10 @@ def read_input(input_filename): inputs ------- - input_filename : a string with a filename/path accessible from the current location + :param input_filename: a string with a filename/path accessible from the current location + :type input_filename: str + :returns: the data from the YAML file. + :rtype: dict """ with open(input_filename, "r") as yaml_file: diff --git a/acme_corp/piano.py b/acme_corp/piano.py new file mode 100644 index 0000000..1a86d3b --- /dev/null +++ b/acme_corp/piano.py @@ -0,0 +1,42 @@ +class Piano: + """ + A grand piano proudly built by ACME corporation. + + Weighing half a ton be careful when hoisting this precariously over + sidewalks. + + .. warning:: + Always use proper rigging techniques when hoisting this above + above any paths that may be occupied by any Road Runners. + """ + + def __init__(self): + self._weight = 1_000 + # start on ground level + self._height = 0 + + def lift(self): + self._height = 3 # [m] + + def drop(self): + pass + + @property + def weight(self): + """ + The current weight of the piano. + + :returns: the current weight. + :rtype: float + """ + return self._weight + + @property + def height(self): + """ + The current height of the piano. + + :returns: the current height. + :rtype: float + """ + return self._height diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..58f53aa --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,35 @@ +# reference: +[project] +name = "acme_corp" +description = "A package, or box, created by the Acme Corporation for all of your Road Runner hunting needs." +# use semantic versioning: +version = "0.0.1" + +readme = "README.md" +requires-python = ">=3.9" +maintainers = [{name = "G. C. Runner", email = "runner@californian.us"}] +authors = [{name = "G. C. Runner", email = "runner@californian.us"}] + +keywords = ["Piano", "Anvil", "Instant Tunnel"] + +# these will be install with `pip install .` +dependencies = ["pyyaml"] + +# these will only be installed with `pip install .[test]` +[project.optional-dependencies] +test =["pytest"] + +[project.scripts] +do_thing = "acme_corp:do_task.do_task" + +# these show up on the left bar on pypi.org +[project.urls] +Homepage = "https://github.com/cnerg/py-template" + +[build-system] +requires = ["setuptools>=64.0.0"] +build-backend = "setuptools.build_meta" + +[tools.pytest.ini_options] +minversion = "6.0" +junit_logging = "all" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test_do_task.py b/tests/test_do_task.py similarity index 84% rename from test_do_task.py rename to tests/test_do_task.py index 74c0348..b73727e 100644 --- a/test_do_task.py +++ b/tests/test_do_task.py @@ -1,4 +1,4 @@ -import do_task +import acme_corp.do_task as do_task def test_perform_action(): args = 'foo' @@ -10,4 +10,4 @@ def test_perform_action(): assert exp == obs - \ No newline at end of file + diff --git a/tests/test_piano.py b/tests/test_piano.py new file mode 100644 index 0000000..9965782 --- /dev/null +++ b/tests/test_piano.py @@ -0,0 +1,22 @@ +import acme_corp + +import pytest + + +@pytest.fixture +def blank_piano(): + return acme_corp.Piano() + + +def test_piano_init(blank_piano): + assert blank_piano.weight == pytest.approx(1_000.0) + assert blank_piano.height == pytest.approx(0.0) + + +def test_lifting_piano(blank_piano): + blank_piano.lift() + assert blank_piano.height == pytest.approx(3) + + +def test_dropping_piano(blank_piano): + pass