Skip to content

Commit

Permalink
Merge pull request #12 from mgcam/prep_for_release
Browse files Browse the repository at this point in the history
Updated documentation
  • Loading branch information
nerdstrike authored Jul 23, 2024
2 parents d8a3d81 + c9e43a7 commit 55a6dfc
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 45 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

## [0.0.1]
## [0.1.0] - 2024-07-23

### Added

# Initial project scaffold
# Initial project scaffold, code and tests
43 changes: 21 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ Provides a Python script, `npg_porch_client`, and a Python client API.

NPG_PORCH_TOKEN environment variable should be set to the value of either
the admin or project-specific token. The token should be pre-registered in
the database that is used by the npg_porch API server.
the database that is used by the `porch` API server.

Can be deployed with pip or poetry in a standard way.
The project can be deployed with pip or poetry in a standard way.

Example of using a client API:

Expand All @@ -18,10 +18,27 @@ Example of using a client API:

pr = PorchRequest(porch_url="https://myporch.com")
response = pr.send(action="list_pipelines")

pr = PorchRequest(
porch_url="https://myporch.com",
pipeline_name="Snakemake_Cardinal",
pipeline_url="https://github.com/wtsi-npg/snakemake_cardinal",
pipeline_version="1.0",
)
response = pr.send(
action="update_task",
task_status="FAILED",
task_input={"id_run": 409, "sample": "Valxxxx", "id_study": "65"},
)
```

By default the client is set up to validate the server's CA certificate.
If the server is using a custom CA certificate, set the path to the certificate.
By default the client validates the certificate of the server's certification
authority (CA). If the server's certificate is signed by a custom CA, set the
`SSL_CERT_FILE` environment variable to the path of the CA's certificate.
Python versions starting from 3.11 seem to have increased security precautions
when validating certificates of custom CAs. It might be necessary to set the
`REQUESTS_CA_BUNDLE` environmental variable, see details
[here](https://requests.readthedocs.io/en/latest/user/advanced/#ssl-cert-verification).

``` bash
export NPG_PORCH_TOKEN='my_token'
Expand All @@ -48,21 +65,3 @@ double quotes in the example below.
--task_json '{"id_run": 409, "sample": "Valxxxx", "id_study": "65"}' \
--status FAILED
```

If using the client API directly from Python, a dictionary should be used.

``` python
from npg_porch_cli.api import PorchRequest

pr = PorchRequest(
porch_url="https://myporch.com",
pipeline_name="Snakemake_Cardinal",
pipeline_url="https://github.com/wtsi-npg/snakemake_cardinal",
pipeline_version="1.0",
)
response = pr.send(
action="update_task",
task_status="FAILED",
task_input={"id_run": 409, "sample": "Valxxxx", "id_study": "65"},
)
```
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "npg_porch_cli"
version = "0.0.1"
version = "0.1.0"
authors = [
"Marina Gourtovaia",
"Kieron Taylor",
Expand Down
108 changes: 93 additions & 15 deletions src/npg_porch_cli/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,25 +138,45 @@ def _validate_status(self) -> str | None:
return status


def get_token():
def get_token() -> str:
"""Gets the value of the porch token from the environment variable.
If the NPG_PORCH_TOKEN is not defined or assigned to am empty string,
raises AuthException.
Returns:
The token.
"""
if NPG_PORCH_TOKEN_ENV_VAR not in os.environ:
raise AuthException("Authorization token is needed")
return os.environ[NPG_PORCH_TOKEN_ENV_VAR]
token = os.environ[NPG_PORCH_TOKEN_ENV_VAR]
if token == "":
raise AuthException("Authorization token is needed")

return token


def list_client_actions() -> list:
def list_client_actions() -> list[str]:
"""Returns a sorted list of currently implemented client actions."""

return sorted(_PORCH_CLIENT_ACTIONS.keys())


def send(action: PorchAction, pipeline: Pipeline = None) -> dict | list:
"""
"""Sends a request to the porch API server.
Sends a request to the porch API server to perform an action defined
by the `action` attribute of the `action` argument. The context of the
query is defined by the pipeline argument.
The server's response is returned as a dictionary or as a list.
Args:
action:
npg_porch_cli.api.PorchAction object
pipeline:
npg_porch_cli.api.Pipeline object
Returns:
The server's response is returned as a Python data structure.
"""

# Get function's definition and then call the function.
Expand All @@ -167,7 +187,16 @@ def send(action: PorchAction, pipeline: Pipeline = None) -> dict | list:


def list_pipelines(action: PorchAction) -> list:
"Returns a listing of all pipelines registered with the porch server."
"""Lists all pipelines registered with the porch server.
Args:
action:
npg_porch_cli.api.PorchAction object
Returns:
A list of dictionaries representing npg_porch_cli.api.Pipeline objects
"""

return send_request(
validate_ca_cert=action.validate_ca_cert,
Expand All @@ -177,10 +206,21 @@ def list_pipelines(action: PorchAction) -> list:


def list_tasks(action: PorchAction, pipeline: Pipeline = None) -> list:
"""
In the pipeline argument is not defined, returns a listing of all tasks
registered with the porch server. If the pipeline argument is defined,
only tasks belonging to this pipeline are listed.
"""Lists tasks.
Args:
action:
npg_porch_cli.api.PorchAction object
pipeline:
npg_porch_cli.api.Pipeline object, optional
Returns:
A list of Python objects, most likely dictionaries, representing registered
tasks.
If the pipeline argument is defined, only tasks belonging to this pipeline
are listed. Otherwise the list contains all tasks registered with the
porch server.
"""

response_obj = send_request(
Expand All @@ -194,8 +234,18 @@ def list_tasks(action: PorchAction, pipeline: Pipeline = None) -> list:
return response_obj


def add_pipeline(action: PorchAction, pipeline: Pipeline):
"Registers a new pipeline with the porch server."
def add_pipeline(action: PorchAction, pipeline: Pipeline) -> dict:
"""Registers a new pipeline with the porch server.
Args:
action:
npg_porch_cli.api.PorchAction object
pipeline:
npg_porch_cli.api.Pipeline object
Returns:
A dictionary representing npg_porch_cli.api.Pipeline object
"""

return send_request(
validate_ca_cert=action.validate_ca_cert,
Expand All @@ -208,7 +258,15 @@ def add_pipeline(action: PorchAction, pipeline: Pipeline):
def add_task(action: PorchAction, pipeline: Pipeline):
"""Registers a new task with the porch server.
The new task is created with the default PENDING status.
Args:
action:
npg_porch_cli.api.PorchAction object
pipeline:
npg_porch_cli.api.Pipeline object
Returns:
A dictionary representing the new task. The status of the new task is
'PENDING'.
"""

if action.task_input is None:
Expand All @@ -226,7 +284,17 @@ def add_task(action: PorchAction, pipeline: Pipeline):


def claim_task(action: PorchAction, pipeline: Pipeline):
"Claims a task that belongs to the previously registered pipeline."
"""Claims a task that belongs to the pipeline.
Args:
action:
npg_porch_cli.api.PorchAction object
pipeline:
npg_porch_cli.api.Pipeline object
Returns:
A dictionary representing the claimed task.
"""

return send_request(
validate_ca_cert=action.validate_ca_cert,
Expand All @@ -237,7 +305,17 @@ def claim_task(action: PorchAction, pipeline: Pipeline):


def update_task(action: PorchAction, pipeline: Pipeline):
"Updates a status of a task."
"""Updates the status of an existing task.
Args:
action:
npg_porch_cli.api.PorchAction object
pipeline:
npg_porch_cli.api.Pipeline object
Returns:
A dictionary representing the updated task.
"""

if action.task_input is None:
raise TypeError(f"task_input cannot be None for action '{action.action}'")
Expand Down
10 changes: 5 additions & 5 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ def json(self):


def test_retrieving_token(monkeypatch):

monkeypatch.delenv(var_name, raising=False)
with pytest.raises(AuthException) as e:
get_token()
assert e.value.args[0] == "Authorization token is needed"

monkeypatch.setenv(var_name, "")
with pytest.raises(AuthException) as e:
get_token()
assert e.value.args[0] == "Authorization token is needed"

monkeypatch.setenv(var_name, "token_xyz")
assert get_token() == "token_xyz"

Expand All @@ -54,14 +58,12 @@ def test_listing_actions():


def test_pipeline_class():

with pytest.raises(TypeError) as e:
Pipeline(name=None, uri="http://some.come", version="1.0")
assert e.value.args[0] == "Pipeline name, uri and version should be defined"


def test_porch_action_class(monkeypatch):

with pytest.raises(TypeError) as e:
PorchAction(porch_url=None, action="list_tasks")
assert e.value.args[0] == "'porch_url' attribute cannot be None"
Expand Down Expand Up @@ -177,7 +179,6 @@ def mock_get_200(*args, **kwargs):


def test_request_validation():

p = Pipeline(uri=url, version="1.0", name="p1")

pa = PorchAction(porch_url=url, action="add_task")
Expand All @@ -196,7 +197,6 @@ def test_request_validation():


def test_sending_request(monkeypatch):

monkeypatch.delenv(var_name, raising=False)
monkeypatch.setenv(var_name, "MY_TOKEN")

Expand Down

0 comments on commit 55a6dfc

Please sign in to comment.