Skip to content

Commit

Permalink
MRG: Merge pull request #72 from octue/release/0.0.17
Browse files Browse the repository at this point in the history
Release/0.0.17
  • Loading branch information
cortadocodes committed Apr 21, 2021
2 parents e99182c + 11b01f6 commit 2c580c9
Show file tree
Hide file tree
Showing 18 changed files with 173 additions and 255 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ jobs:

tests:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '#skip_ci_tests')"
if: "!contains(github.event.head_commit.message, 'skip_ci_tests')"
env:
USING_COVERAGE: '3.8'
strategy:
matrix:
python: [3.6, 3.7, 3.8]
python: [3.8]
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Checkout Repository
uses: actions/checkout@v2
Expand Down Expand Up @@ -73,4 +74,3 @@ jobs:
user: __token__
password: ${{ secrets.PYPI_TOKEN }}
verbose: true

28 changes: 28 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Publish on merge of release/x.y.z into main

# Only trigger when a pull request into main branch is closed.
on:
pull_request:
types: [closed]
branches:
- main

jobs:
release:
# This job will only run if the PR has been merged (and not closed without merging).
if: github.event.pull_request.merged == true && startsWith( github.head_ref, 'release/' )
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Get package version
run: echo "PACKAGE_VERSION=$(python setup.py --version)" >> $GITHUB_ENV
- name: Create Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, no need to create your own.
with:
tag_name: ${{ env.PACKAGE_VERSION }}
release_name: ${{ github.event.pull_request.title }}
body: ${{ github.event.pull_request.body }}
draft: false
prerelease: false
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ repos:
- id: check-added-large-files
args: ['--maxkb=10240']

- repo: https://github.com/pre-commit/mirrors-isort
rev: v4.3.21
- repo: https://github.com/PyCQA/isort
rev: 5.7.0
hooks:
- id: isort

- repo: https://github.com/psf/black
rev: 19.10b0
rev: 20.8b1
hooks:
- id: black
args: ['--line-length', '120']
language_version: python3

- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.1
rev: 3.8.4
hooks:
- id: flake8
language_version: python3
Expand Down
7 changes: 3 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

setup(
name="twined",
version="0.0.16",
version="0.0.17",
py_modules=[],
install_requires=["jsonschema ~= 3.2.0", "python-dotenv"],
url="https://www.github.com/octue/twined",
Expand All @@ -32,10 +32,9 @@
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries :: Python Modules",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Operating System :: OS Independent",
],
python_requires=">=3.6",
python_requires=">=3.8",
keywords=["digital", "twins", "data", "services", "python", "schema"],
)
4 changes: 2 additions & 2 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@


class BaseTestCase(unittest.TestCase):
""" Base test case for twined:
- sets a path to the test data directory
"""Base test case for twined:
- sets a path to the test data directory
"""

def setUp(self):
Expand Down
41 changes: 16 additions & 25 deletions tests/test_children.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@


class TestChildrenTwine(BaseTestCase):
""" Tests related to the twine itself - ensuring that valid and invalid
`children` entries in a twine file work as expected
"""
"""Tests related to the twine itself - ensuring that valid and invalid
`children` entries in a twine file work as expected
"""

def test_invalid_children_dict_not_array(self):
""" Ensures InvalidTwine exceptions are raised when instantiating twines where `children` entry is incorrectly
"""Ensures InvalidTwine exceptions are raised when instantiating twines where `children` entry is incorrectly
specified as a dict, not an array
"""
with self.assertRaises(exceptions.InvalidTwine):
Twine(source="""{"children": {}}""")

def test_invalid_children_no_key(self):
""" Ensures InvalidTwine exceptions are raised when instantiating twines where a child
"""Ensures InvalidTwine exceptions are raised when instantiating twines where a child
is specified without the required `key` field
"""
source = """
Expand All @@ -30,8 +30,7 @@ def test_invalid_children_no_key(self):
Twine(source=source)

def test_valid_children(self):
""" Ensures that a twine with one child can be instantiated correctly.
"""
"""Ensures that a twine with one child can be instantiated correctly."""
source = """
{
"children": [{"key": "gis", "purpose": "The purpose.", "notes": "Some notes.", "filters": "tags:gis"}]
Expand All @@ -40,15 +39,13 @@ def test_valid_children(self):
self.assertEqual(len(Twine(source=source).children), 1)

def test_empty_children(self):
""" Ensures that a twine file will validate with an empty list object as children
"""
"""Ensures that a twine file will validate with an empty list object as children"""
twine = Twine(source="""{"children": []}""")
self.assertEqual(len(twine.children), 0)


class TestChildrenValidation(BaseTestCase):
""" Tests related to whether validation of children occurs successfully (given a valid twine)
"""
"""Tests related to whether validation of children occurs successfully (given a valid twine)"""

VALID_TWINE_WITH_CHILDREN = """
{
Expand All @@ -71,19 +68,16 @@ class TestChildrenValidation(BaseTestCase):
"""

def test_no_children(self):
""" Test that a twine with no children will validate on an empty children input
"""
"""Test that a twine with no children will validate on an empty children input"""
Twine().validate_children(source=[])

def test_missing_children(self):
""" Test that a twine with children will not validate on an empty children input
"""
"""Test that a twine with children will not validate on an empty children input"""
with self.assertRaises(exceptions.InvalidValuesContents):
Twine(source=self.VALID_TWINE_WITH_CHILDREN).validate_children(source=[])

def test_extra_children(self):
""" Test that a twine with no children will not validate a non-empty children input
"""
"""Test that a twine with no children will not validate a non-empty children input"""
with self.assertRaises(exceptions.InvalidValuesContents):
Twine().validate_children(source=self.VALID_CHILD_VALUE)

Expand All @@ -95,8 +89,7 @@ def test_backend_cannot_be_empty(self):
Twine().validate_children(source=single_child_missing_backend)

def test_extra_key_validation_on_empty_twine(self):
""" Test that children with extra data will not raise a validation error on an empty twine.
"""
"""Test that children with extra data will not raise a validation error on an empty twine."""
children_values_with_extra_data = """
[
{"key": "gis", "id": "id", "uri_env_name": "VAR_NAME", "an_extra_key": "not a problem if present"},
Expand All @@ -108,7 +101,7 @@ def test_extra_key_validation_on_empty_twine(self):
Twine().validate_children(source=children_values_with_extra_data)

def test_extra_key_validation_on_valid_twine(self):
""" Test that children with extra data will not raise a validation error on a non-empty valid twine.
"""Test that children with extra data will not raise a validation error on a non-empty valid twine.
# TODO review this behaviour - possibly should raise an error but allow for a user specified extra_data property
"""
single_child_with_extra_data = """
Expand All @@ -130,8 +123,7 @@ def test_extra_key_validation_on_valid_twine(self):
twine.validate_children(source=single_child_with_extra_data)

def test_invalid_env_name(self):
""" Test that a child uri env name not in ALL_CAPS_SNAKE_CASE doesn't validate
"""
"""Test that a child uri env name not in ALL_CAPS_SNAKE_CASE doesn't validate"""
child_with_invalid_environment_variable_name = """
[
{
Expand All @@ -146,13 +138,12 @@ def test_invalid_env_name(self):
Twine().validate_children(source=child_with_invalid_environment_variable_name)

def test_invalid_json(self):
""" Tests that a children entry with invalid json will raise an error
"""
"""Tests that a children entry with invalid json will raise an error"""
with self.assertRaises(exceptions.InvalidValuesJson):
Twine(source=self.VALID_TWINE_WITH_CHILDREN).validate_children(source="[")

def test_valid(self):
""" Test that a valid twine will validate valid children
"""Test that a valid twine will validate valid children
Valiantly and Validly validating validity since 1983.
To those reading this, know that YOU'RE valid.
"""
Expand Down
45 changes: 13 additions & 32 deletions tests/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@


class TestCredentialsTwine(BaseTestCase):
""" Tests related to the twine itself - ensuring that valid and invalid `credentials` entries in a twine file work
"""Tests related to the twine itself - ensuring that valid and invalid `credentials` entries in a twine file work
as expected.
"""

def test_fails_on_no_name(self):
""" Ensures InvalidTwine exceptions are raised when instantiating twines with a missing `name` field in a
"""Ensures InvalidTwine exceptions are raised when instantiating twines with a missing `name` field in a
credential.
"""
invalid_credentials_no_name_twine = """
Expand All @@ -29,7 +29,7 @@ def test_fails_on_no_name(self):
Twine(source=invalid_credentials_no_name_twine)

def test_fails_on_lowercase_name(self):
""" Ensures InvalidTwine exceptions are raised when instantiating twines with lowercase letters in the `name`
"""Ensures InvalidTwine exceptions are raised when instantiating twines with lowercase letters in the `name`
field.
"""
invalid_credentials_lowercase_name_twine = """
Expand All @@ -47,7 +47,7 @@ def test_fails_on_lowercase_name(self):
Twine(source=invalid_credentials_lowercase_name_twine)

def test_fails_on_dict(self):
""" Ensures InvalidTwine exceptions are raised when instantiating twines with invalid `credentials` entries
"""Ensures InvalidTwine exceptions are raised when instantiating twines with invalid `credentials` entries
(given as a dict, not an array).
"""
invalid_credentials_dict_not_array_twine = """
Expand Down Expand Up @@ -79,8 +79,7 @@ def test_fails_on_name_whitespace(self):


class TestCredentialsValidation(BaseTestCase):
""" Tests related to whether validation of children occurs successfully (given a valid twine)
"""
"""Tests related to whether validation of children occurs successfully (given a valid twine)"""

VALID_CREDENTIALS_TWINE = """
{
Expand All @@ -94,50 +93,32 @@ class TestCredentialsValidation(BaseTestCase):
"purpose": "Token for accessing a 3rd party API service"
},
{
"name": "SECRET_THE_THIRD",
"purpose": "Usually a big secret but sometimes has a convenient non-secret default, like a sandbox or local database",
"default": "postgres://pguser:pgpassword@localhost:5432/pgdb"
"name": "SECRET_THE_THIRD"
}
]
}
"""

def test_no_credentials(self):
""" Test that a twine with no credentials will validate straightforwardly
"""
"""Test that a twine with no credentials will validate straightforwardly"""
twine = Twine(source=VALID_SCHEMA_TWINE)
twine.validate_credentials()

def test_missing_credentials(self):
""" Test that a twine with credentials will not validate where they are missing from the environment
"""
"""Test that a twine with credentials will not validate where they are missing from the environment"""
twine = Twine(source=self.VALID_CREDENTIALS_TWINE)
with self.assertRaises(exceptions.CredentialNotFound):
twine.validate_credentials()

def test_default_credentials(self):
""" Test that a twine with credentials will validate where ones with defaults are missing from the environment
"""
twine = Twine(source=self.VALID_CREDENTIALS_TWINE)
with mock.patch.dict(os.environ, {"SECRET_THE_FIRST": "a value", "SECRET_THE_SECOND": "another value"}):
credentials = twine.validate_credentials()

self.assertIn("SECRET_THE_FIRST", credentials.keys())
self.assertIn("SECRET_THE_SECOND", credentials.keys())
self.assertIn("SECRET_THE_THIRD", credentials.keys())
self.assertEqual(credentials["SECRET_THE_THIRD"], "postgres://pguser:pgpassword@localhost:5432/pgdb")

def test_nondefault_credentials(self):
""" Test that the environment will override a default value for a credential
"""
def test_credentials(self):
""" Test that the environment will override a default value for a credential."""
twine = Twine(source=self.VALID_CREDENTIALS_TWINE)
with mock.patch.dict(
os.environ,
{"SECRET_THE_FIRST": "a value", "SECRET_THE_SECOND": "another value", "SECRET_THE_THIRD": "nondefault"},
{"SECRET_THE_FIRST": "a value", "SECRET_THE_SECOND": "another value", "SECRET_THE_THIRD": "value"},
):
credentials = twine.validate_credentials()

self.assertEqual(credentials["SECRET_THE_THIRD"], "nondefault")
twine.validate_credentials()
self.assertEqual(os.environ["SECRET_THE_THIRD"], "value")


if __name__ == "__main__":
Expand Down
9 changes: 3 additions & 6 deletions tests/test_manifest_strands.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@


class TestManifestStrands(BaseTestCase):
""" Testing operation of the Twine class for validation of data using strands which require manifests
"""
"""Testing operation of the Twine class for validation of data using strands which require manifests"""

VALID_MANIFEST_STRAND = """
{
Expand Down Expand Up @@ -41,8 +40,7 @@ class TestManifestStrands(BaseTestCase):
"""

def test_missing_manifest_files(self):
""" Ensures that if you try to read values from missing files, the right exceptions get raised
"""
"""Ensures that if you try to read values from missing files, the right exceptions get raised"""
twine = Twine(source=self.VALID_MANIFEST_STRAND)
file = os.path.join(self.path, "not_a_file.json")

Expand All @@ -56,8 +54,7 @@ def test_missing_manifest_files(self):
twine.validate_output_manifest(source=file)

def test_valid_manifest_files(self):
""" Ensures that a manifest file will validate
"""
"""Ensures that a manifest file will validate"""
valid_configuration_manifest = """
{
"id": "3ead7669-8162-4f64-8cd5-4abe92509e17",
Expand Down

0 comments on commit 2c580c9

Please sign in to comment.