Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
6b95f8e
REF: Use dict comprehensions for dict construction
cortadocodes Oct 18, 2020
613220a
REF: Use generator of tuples rather than dict
cortadocodes Oct 18, 2020
7dff513
REF: Avoid repeating usage of append method
cortadocodes Oct 19, 2020
2ddbe85
REF: Remove redundant conditions
cortadocodes Oct 21, 2020
f74c693
REF: Simplify packaged templates tuple
cortadocodes Oct 22, 2020
91a72a8
TST: Reduce repeated literals and code in tests
cortadocodes Oct 23, 2020
87c68ad
REF: Use os.sep for path part separators
cortadocodes Oct 23, 2020
766cac3
TST: Narrow assertions in dataset tests
cortadocodes Oct 23, 2020
58ab972
REF: Remove unused module logger
cortadocodes Oct 23, 2020
bd7de63
REF: Factor out repeated class definitions in tests
cortadocodes Oct 23, 2020
a27f3b6
REF: Avoid overriding built-in dir keyword
cortadocodes Oct 23, 2020
0aaee9d
FIX Correct python environment specified
thclark Oct 27, 2020
3b4bc28
Merge pull request #22 from octue/master
thclark Oct 27, 2020
b3f8fb7
Merge pull request #21 from octue/refactor
thclark Oct 27, 2020
451c756
Merge pull request #23 from octue/fix/tox-environment
thclark Oct 27, 2020
03a8e2c
DEPS Update dependencies of the fractal example to work with twined-s…
thclark Oct 27, 2020
e59518e
REV: Remove octue_version decorator
cortadocodes Oct 27, 2020
c000dfd
IMP: Enable CLI again and add --version option
cortadocodes Oct 28, 2020
111f47f
REF: Mirror package structure in tests package
cortadocodes Oct 28, 2020
538f557
FIX: Update relative path to base test module
cortadocodes Oct 28, 2020
febd8f9
TST: Test version CLI command
cortadocodes Oct 28, 2020
b2b649f
IMP: Add entry point to octue CLI
cortadocodes Oct 29, 2020
f737c73
IMP: Add -h option for help command
cortadocodes Oct 29, 2020
0e6d530
TST: Test help CLI command; refactor version test
cortadocodes Oct 29, 2020
695bc49
REV: Remove deprecated log_dir option from CLI
cortadocodes Oct 31, 2020
2b32e9c
IMP: Allow data_dir and/or specific directories to be supplied
cortadocodes Oct 31, 2020
5ec3a7e
IMP: Show defaults for new CLI options
cortadocodes Oct 31, 2020
d1aaef2
REV: Remove option to pass in JSON strings as inputs
cortadocodes Oct 31, 2020
b53b370
REF: Move directory options into run command
cortadocodes Oct 31, 2020
971f453
FIX: Return wrapped run function from decorator
cortadocodes Oct 31, 2020
b74a496
REV: Remove pass_analysis function
cortadocodes Oct 31, 2020
bc2d6a0
REV: Remove invocation of CLI from app.py
cortadocodes Oct 31, 2020
39f8e5d
TST: Test that run command can be added to CLI via decorator
cortadocodes Oct 31, 2020
94442dc
REF: Remove function for getting version
cortadocodes Oct 31, 2020
63e74d2
TST: Test CLI run command
cortadocodes Nov 3, 2020
e22f3dc
REF: Add run command to CLI
cortadocodes Nov 3, 2020
ceb955d
REF: Use absolute path in tests
cortadocodes Nov 3, 2020
bea413f
TST: Test --data-dir for run command; update docstrings
cortadocodes Nov 3, 2020
b997b18
REF: Simplify default argument creation
cortadocodes Nov 3, 2020
6565f20
REF: Remove duplicate function
cortadocodes Nov 3, 2020
602c221
REF: Remove need for #noqa by using __all__
cortadocodes Nov 4, 2020
0be00eb
REF: Make file checking DRYer
cortadocodes Nov 4, 2020
e607752
REF: Refactor paths used in CLI tests
cortadocodes Nov 4, 2020
67fb95b
REF: Remove manifests from test data directory
cortadocodes Nov 4, 2020
bbc4554
IMP: Pass configuration manifest to Runner
cortadocodes Nov 4, 2020
8ac7cf6
IMP: Pass input manifest to Runner
cortadocodes Nov 4, 2020
a69d865
REF: Simplify test paths
cortadocodes Nov 4, 2020
ecbda83
REV: Remove unnecessary setter method for read-only attributes
cortadocodes Nov 4, 2020
24af29d
Merge pull request #26 from octue/refactor-simplify-cli
thclark Nov 17, 2020
7d6b8af
Merge pull request #24 from octue/devops/fractal-requirements
thclark Nov 17, 2020
105e514
FIX making sure the app path is assigned to the instance
thclark Nov 17, 2020
46c3427
STY Removed flake8 rule
thclark Nov 17, 2020
012f707
FIX Issue #27
thclark Nov 17, 2020
2b72f5b
STY Removed print statement
thclark Nov 17, 2020
5ca0ec8
Merge pull request #28 from octue/fix/issue-27
thclark Nov 17, 2020
b0b2477
GIT Avoiding conflict between flake8 implementations
thclark Nov 17, 2020
55995e9
STY Reapplied style guide throughout
thclark Nov 17, 2020
373c92a
TST Removed unused test
thclark Nov 17, 2020
d2abdbd
Merge branch 'main' into release/0.1.4
thclark Nov 17, 2020
a6a0ae7
DOC Minor tweaks to CLI helpstrings
thclark Nov 17, 2020
234441a
DOC Improved help of the app_src arg because it doesn't accept path_like
thclark Nov 17, 2020
903f8b6
REF Removed old placeholder for injection of an analysis object
thclark Nov 17, 2020
45cc2f2
DOC Improfed main helpstring of CLI and added an internal todo
thclark Nov 17, 2020
9545c43
REF Refactored definitions out so they're importable before the CLI a…
thclark Nov 18, 2020
1080524
IMP Added a finalise mehtod to the analysis object, allowing us to se…
thclark Nov 18, 2020
9f8284c
IMP Added finalisation and set return code from the CLI to 0
thclark Nov 18, 2020
da13c30
FIX Correctly saving outputs to file
thclark Nov 18, 2020
33cd503
IMP Removing unused tmp_dir per issue #30
thclark Nov 18, 2020
80f20ed
IMP Removing unused tmp_dir per issue #30
thclark Nov 18, 2020
3c7a247
DOC Better description of how the run funciton works
thclark Nov 18, 2020
2bf6de5
REF Updated fractal templat to remove old entrypoint
thclark Nov 18, 2020
9ed9a65
IMP Removed hard directory checking per #29
thclark Nov 18, 2020
cfee7ef
REF Removed the file path getter to utils module so its reusable
thclark Nov 18, 2020
239f0bd
TST Fixed tests so they use teh finalise method
thclark Nov 18, 2020
8169370
REF Removed unused path hinting code, possibly for reintroduction pen…
thclark Nov 18, 2020
96bd28a
Merge branch 'release/0.1.4' of https://github.com/octue/octue-sdk-py…
thclark Nov 18, 2020
327524d
GIT Removed old master default branch
thclark Nov 18, 2020
abc14c7
REF Removed unused imports from twined
thclark Nov 18, 2020
817c56c
IMP Made error mesage more helpful
thclark Nov 19, 2020
a2c4c1e
FIX Workaround problem of datasets and datafiles not being instantiat…
thclark Nov 19, 2020
b818ef2
IMP Improved error message for better diagnosis of bad manifests
thclark Nov 19, 2020
f6094e0
TST Removed misleading passing test
thclark Nov 19, 2020
c9f3c4a
DOC Clarified that logger is a class variable to avoid confusion
thclark Nov 20, 2020
5d98b6c
DEPS Updated dependencies in teh fractal template app
thclark Nov 20, 2020
979d86c
DEPS Updated installed developer dependencies for template apps
thclark Nov 20, 2020
3e09647
DEPS Updated installed developer dependencies for template apps
thclark Nov 20, 2020
2118ff5
FIX Removed old assignment of self.files that was causing failure of …
thclark Nov 20, 2020
ef3b055
STY Typo
thclark Nov 20, 2020
4f51063
DOC Added a TODO notice to refactor taggable ot have a generic mixin …
thclark Nov 20, 2020
0bd63a2
IMP New Pathable mixin as a robust way of handling file paths in mani…
thclark Nov 20, 2020
8335498
TST Added tests for base mixin
thclark Nov 20, 2020
2528a90
IMP Updated Datafiles, Datasets and Manifests for use of Pathable thr…
thclark Nov 20, 2020
79dcb9d
FIX Updated to use the absolute_path of the result file
thclark Nov 20, 2020
7c4e92a
FIX Manifest prepare method also instantiates logger
thclark Nov 20, 2020
e50a4bd
DEPS Updated dependencies from the using-manifests test app
thclark Nov 20, 2020
8bb1d31
FIX Enabled Serialisables to specifically exclude fields
thclark Nov 20, 2020
f735632
FIX Hooked up output data path into the runner
thclark Nov 20, 2020
a8bcf9d
REF Removed duplicated dump code
thclark Nov 20, 2020
9ae91d0
IMP Added context manager for files and made serialisable
thclark Nov 20, 2020
d5c9694
IMP Added a template app showing how to use manifests
thclark Nov 20, 2020
f1e81fb
GIT Added gitignore to the template app
thclark Nov 20, 2020
24b683f
DEPS Revert to twined==0.0.13 - same functionality but there's an iss…
thclark Nov 20, 2020
7e116c9
Merge branch 'release/0.1.4' into doc/update-usage
thclark Nov 20, 2020
2be4c9b
Merge pull request #33 from octue/doc/update-usage
thclark Nov 20, 2020
c2ebfb9
STY Removed print statements violating flake8
thclark Nov 20, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ repos:
rev: 3.8.1
hooks:
- id: flake8
additional_dependencies: [flake8-isort]
language_version: python3

- repo: https://github.com/thclark/pre-commit-sphinx
rev: 0.0.1
Expand All @@ -42,7 +42,6 @@ repos:
hooks:
- id: check-branch-name
args:
- '^master$'
- '^main$'
- '^development$'
- '^devops/([a-z][a-z0-9]*)(-[a-z0-9]+)*$'
Expand Down
7 changes: 5 additions & 2 deletions octue/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
from .cli import octue_cli, octue_run, octue_version, pass_analysis # noqa: F401
from .runner import LOG_FORMAT, Runner # noqa: F401
from .cli import octue_cli
from .runner import LOG_FORMAT, Runner


__all__ = "LOG_FORMAT", "octue_cli", "Runner"
190 changes: 58 additions & 132 deletions octue/cli.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import importlib
import os
import sys
from functools import update_wrapper
import click
import pkg_resources


FOLDERS = (
"configuration",
"input",
"log",
"tmp",
"output",
)
from octue.definitions import FOLDER_DEFAULTS, MANIFEST_FILENAME, VALUES_FILENAME
from octue.runner import Runner


@click.group()
@click.group(context_settings={"help_option_names": ["-h", "--help"]})
@click.option(
"--id",
default=None,
Expand Down Expand Up @@ -43,146 +36,79 @@
show_default=True,
help="Forces a reset of analysis cache and outputs [For future use, currently not implemented]",
)
@click.version_option(version=pkg_resources.get_distribution("octue").version)
@click.pass_context
def octue_cli(ctx, id, skip_checks, log_level, force_reset):
""" Octue CLI, enabling a data service / digital twin to be run like a command line application.

When acting in CLI mode, results are read from and written to disk (see
https://octue-python-sdk.readthedocs.io/en/latest/ for how to run your application directly without the CLI).
Once your application has run, you'll be able to find output values and manifest in your specified --output-dir.
"""
# TODO Forward command line options to runner via ctx
ctx.ensure_object(dict)


@octue_cli.command()
@click.option(
"--configuration-values",
"--app-dir",
type=click.Path(),
default="<data-dir>/input/input_values.json",
default=".",
show_default=True,
help="Source for configuration_values strand data.",
help="Directory containing your source code (app.py)",
)
@click.option(
"--configuration-manifest",
"--data-dir",
type=click.Path(),
default="<data-dir>/input/input_values.json",
default=".",
show_default=True,
help="Source for configuration_manifest strand data.",
help="Location of directories containing configuration values and manifest, input values and manifest, and output "
"directory.",
)
@click.option(
"--input-values",
"--config-dir",
type=click.Path(),
default="<data-dir>/input/input_values.json",
default=None,
show_default=True,
help="Source for input_values strand data.",
help="Directory containing configuration (overrides --data-dir).",
)
@click.option(
"--input-manifest",
"--input-dir",
type=click.Path(),
default="<data-dir>/input/input_manifest.json",
default=None,
show_default=True,
help="Source for input_manifest strand data.",
help="Directory containing input (overrides --data-dir).",
)
@click.option(
"--output-dir",
type=click.Path(),
default="output",
show_default=False,
help="Directory to write outputs as files.",
default=None,
show_default=True,
help="Directory to write outputs as files (overrides --data-dir).",
)
@click.option(
"--log-dir", type=click.Path(), default="logs", show_default=True, help="Path to the location of log files",
"--twine", type=click.Path(), default="twine.json", show_default=True, help="Location of Twine file.",
)
@click.pass_context
def octue_cli(
ctx,
id,
skip_checks,
log_level,
force_reset,
configuration_values,
configuration_manifest,
input_values,
input_manifest,
data_dir,
input_dir,
tmp_dir,
output_dir,
log_dir,
):
""" Octue CLI, enabling a data service / digital twin to be run like a command line application.

Provide sources of configuration and/or input data and run the app. A source can be:

- A path (relative or absolute) to a directory containing a <strand>.json file (eg `path/to/dir`).
- A path to a <strand>.json file (eg `path/to/configuration_values.json`).
- A literal JSON string (eg `{"n_iterations": 10}`.

"""

# We want to show meaningful defaults in the CLI help but unfortunately have to strip out the displayed values here
if input_values.startswith("<data-dir>/"):
input_dir = None # noqa
if log_dir.startswith("<data-dir>/"):
log_dir = None # noqa
if output_dir.startswith("<data-dir>/"):
output_dir = None # noqa

ctx.ensure_object(dict)
ctx.obj["analysis"] = "VIBRATION"


def pass_analysis(f):
@click.pass_context
def new_func(ctx, *args, **kwargs):
return ctx.invoke(f, ctx.obj["analysis"], *args, **kwargs)

return update_wrapper(new_func, f)


def octue_run(f):
""" Decorator for the main `run` function which adds a command to the CLI and prepares analysis ready for the run
"""

@octue_cli.command()
@pass_analysis
def run(*args, **kwargs):
return f(*args, **kwargs)

return update_wrapper(run, f)


def octue_version(f):
""" Decorator for the main `version` function which adds a command to the CLI
"""

@octue_cli.command()
def version(*args, **kwargs):
return f(*args, **kwargs)

return update_wrapper(version, f)


def unwrap(fcn):
""" Recurse through wrapping to get the raw function without decorators.
"""
if hasattr(fcn, "__wrapped__"):
return unwrap(fcn.__wrapped__)
return fcn


class AppFrom:
""" Context manager that allows us to temporarily add an app's location to the system path and
extract its run function

with AppFrom('/path/to/dir') as app:
Runner().run(app)

"""

def __init__(self, app_path="."):
self.app_path = os.path.abspath(os.path.normpath(app_path))
self.app_module = None

def __enter__(self):
sys.path.insert(0, self.app_path)
self.app_module = importlib.import_module("app")
return self

def __exit__(self, exc_type, exc_value, traceback):
if self.app_path in sys.path:
sys.path.remove(self.app_path)

@property
def run(self):
""" Returns the unwrapped run function from app.py in the application's root directory
"""
return unwrap(self.app_module.run)
def run(app_dir, data_dir, config_dir, input_dir, output_dir, twine):
config_dir = config_dir or os.path.join(data_dir, FOLDER_DEFAULTS["configuration"])
input_dir = input_dir or os.path.join(data_dir, FOLDER_DEFAULTS["input"])
output_dir = output_dir or os.path.join(data_dir, FOLDER_DEFAULTS["output"])

runner = Runner(
twine=twine,
configuration_values=os.path.join(config_dir, VALUES_FILENAME),
configuration_manifest=os.path.join(config_dir, MANIFEST_FILENAME),
)
analysis = runner.run(
app_src=app_dir,
input_values=os.path.join(input_dir, VALUES_FILENAME),
input_manifest=os.path.join(input_dir, MANIFEST_FILENAME),
output_manifest_path=os.path.join(output_dir, MANIFEST_FILENAME),
)
analysis.finalise(output_dir=output_dir)
return 0


if __name__ == "__main__":
args = sys.argv[1:] if len(sys.argv) > 1 else []
octue_cli(args)
26 changes: 26 additions & 0 deletions octue/definitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FOLDER_DEFAULTS = {
"configuration": "configuration",
"input": "input",
"tmp": "tmp",
"output": "output",
}

VALUES_FILENAME = "values.json"

MANIFEST_FILENAME = "manifest.json"

STRAND_FILENAME_MAP = {
"configuration_values": VALUES_FILENAME,
"configuration_manifest": MANIFEST_FILENAME,
"input_values": VALUES_FILENAME,
"input_manifest": MANIFEST_FILENAME,
"output_values": VALUES_FILENAME,
"output_manifest": MANIFEST_FILENAME,
}


# TODO this should probably be defined in twined
OUTPUT_STRANDS = ("output_values", "output_manifest")

# TODO this should probably be defined in twined
RUN_STRANDS = ("input_values", "input_manifest", "credentials", "children")
13 changes: 9 additions & 4 deletions octue/mixins/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from .identifiable import Identifiable # noqa: F401
from .loggable import Loggable # noqa: F401
from .serialisable import Serialisable # noqa: F401
from .taggable import Taggable # noqa:F401
from .base import MixinBase
from .identifiable import Identifiable
from .loggable import Loggable
from .pathable import Pathable
from .serialisable import Serialisable
from .taggable import Taggable


__all__ = "Identifiable", "Loggable", "MixinBase", "Pathable", "Serialisable", "Taggable"
22 changes: 22 additions & 0 deletions octue/mixins/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class MixinBase:
""" Allows you to use any combination of mixin classes which pass unused *args and **kwargs up to their superclass,
without encountering:
```
Error
Traceback (most recent call last):
super().__init__(*args, **kwargs)
TypeError: object.__init__() takes no parameters
```
on initialisation.

The case of passing extra args and kwargs to your class constructor which aren't popped by the various
mixins is still handled safely with the same error (to prevent loss of variables and poorly defined behaviour
later).
"""

def __init__(self, *args, **kwargs):
""" Constructor for ResourceBase
"""
if (len(args) > 0) or (len(kwargs.keys()) > 0):
raise TypeError("object.__init__() takes no parameters")
super().__init__()
4 changes: 0 additions & 4 deletions octue/mixins/identifiable.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,3 @@ def __repr__(self):
@property
def id(self):
return self._id

@id.setter
def id(self, value):
raise InvalidInputException(f"You cannot set the id of an already-instantiated {self.__class__.__name__}")
3 changes: 3 additions & 0 deletions octue/mixins/loggable.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
class Loggable:
""" Mixin to allow instantiation of a class with a logger, or by default use the module logger from that class

The attached logger is a class variable, so all Resources of the same type inheriting from Loggable will share the
same logger instance; this can be confusing if you overload __init_logger__ in multiple different ways.

```
class MyResource(Logged):
def do_something(self):
Expand Down
Loading