Skip to content

Commit

Permalink
Merge pull request #16 from paketb0te/main
Browse files Browse the repository at this point in the history
Add type hints
  • Loading branch information
willthames authored Oct 11, 2022
2 parents 343df18 + 59f60a2 commit cb331df
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tox.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
matrix:
platform: [ubuntu-latest, windows-latest]
python-version: [2.7, 3.9]
python-version: ["3.8", "3.9", "3.10"]

steps:
- uses: actions/checkout@v1
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
*.pyc
dist/
.tox
.venv
2 changes: 1 addition & 1 deletion src/kubernetes_validate/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from kubernetes_validate.version import __version__


def main():
def main() -> int:
parser = argparse.ArgumentParser(description='validate a kubernetes resource definition')
parser.add_argument('-k', '--kubernetes-version', action='append',
help='version of kubernetes against which to validate. Defaults to %s' %
Expand Down
56 changes: 37 additions & 19 deletions src/kubernetes_validate/utils.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
from __future__ import print_function

from distutils.version import LooseVersion
import json
import jsonschema
import os
import platform
import pkg_resources
import re
import sys
from distutils.version import LooseVersion
from typing import Any, Dict, Generator, List

import jsonschema
import pkg_resources
import yaml

from kubernetes_validate.version import __version__


class ValidationError(jsonschema.ValidationError):
def __init__(self, caught, version):
def __init__(self, caught: Exception, version: str):
self.version = version
for attr, value in caught.__dict__.items():
self.__dict__[attr] = value


class SchemaNotFoundError(Exception):
def __init__(self, kind, version, api_version):
def __init__(self, kind: str, version: str, api_version: str):
self.kind = kind
self.version = version
self.api_version = api_version
Expand All @@ -30,33 +32,33 @@ def __init__(self, kind, version, api_version):


class VersionNotSupportedError(Exception):
def __init__(self, version):
def __init__(self, version: str):
self.version = version
self.message = ("kubernetes-validate does not support version %s" % self.version)


class InvalidSchemaError(Exception):
def __init__(self, message):
def __init__(self, message: str):
self.message = message


def all_versions():
def all_versions() -> List[str]:
schemas = pkg_resources.resource_listdir('kubernetes_validate', '/kubernetes-json-schema')
version_regex = re.compile(r'^v([^-]*).*')
return sorted([version_regex.sub(r"\1", schema) for schema in schemas if version_regex.match(schema)],
key=LooseVersion)


def major_minor(version):
def major_minor(version: str) -> str:
version_regex = re.compile(r'^(\d+\.\d+).*')
return version_regex.sub(r"\1", version)


def latest_version():
def latest_version() -> str:
return all_versions()[-1]


def validate(data, desired_version, strict=False):
def validate(data: Dict[str, Any], desired_version: str, strict: bool = False) -> str:
# strip initial v from version (I keep forgetting, so other people will too)
if desired_version.startswith('v'):
desired_version = desired_version[1:]
Expand Down Expand Up @@ -84,7 +86,7 @@ def validate(data, desired_version, strict=False):
api_version=data['apiVersion'])
try:
schema = json.load(f)
except json.JsonDecodeError:
except json.decoder.JSONDecodeError:
raise InvalidSchemaError("Couldn't parse schema %s" % schema_file)
finally:
f.close()
Expand All @@ -102,15 +104,22 @@ def validate(data, desired_version, strict=False):
return major_minor(version)
except jsonschema.ValidationError as e:
raise ValidationError(e, version=major_minor(version))
except jsonschema.exceptions.RefResolutionError:
except jsonschema.RefResolutionError:
raise


def kn(resource):
def kn(resource: dict) -> str:
return "%s/%s" % (resource["kind"].lower(), resource["metadata"]["name"])


def validate_resource(resource, filename, version, strict, quiet, no_warn):
def validate_resource(
resource: dict,
filename: str,
version: str,
strict: bool,
quiet: bool,
no_warn: bool,
) -> int:
try:
validated_version = validate(resource, version, strict)
if not quiet:
Expand All @@ -134,7 +143,7 @@ def validate_resource(resource, filename, version, strict, quiet, no_warn):
return 0


def construct_value(load, node):
def construct_value(load: yaml.Loader, node: yaml.ScalarNode) -> Generator[str, None, None]:
if not isinstance(node, yaml.ScalarNode):
raise yaml.constructor.ConstructorError(
"while constructing a value",
Expand All @@ -144,7 +153,7 @@ def construct_value(load, node):
yield str(node.value)


def resources_from_file(filename):
def resources_from_file(filename: str) -> List[Dict]:
# Handle nodes that start with '='
# See https://github.com/yaml/pyyaml/issues/89
yaml.SafeLoader.add_constructor(u'tag:yaml.org,2002:value', construct_value)
Expand All @@ -166,8 +175,17 @@ def resources_from_file(filename):
return data


def validate_file(filename, version, strict, quiet, no_warn):
def validate_file(
filename: str, version: str, strict: bool, quiet: bool, no_warn: bool
) -> int:
rc = 0
for resource in resources_from_file(filename):
rc |= validate_resource(resource, filename, version, strict, quiet, no_warn)
rc |= validate_resource(
resource=resource,
filename=filename,
version=version,
strict=strict,
quiet=quiet,
no_warn=no_warn,
)
return rc
4 changes: 4 additions & 0 deletions test-deps.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ pytest
pep8-naming
tox
wheel
mypy
types-jsonschema
types-setuptools
types-PyYAML
17 changes: 13 additions & 4 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
[tox]
minversion = 1.6
envlist = py{27,39}-{pytest,flake8}
envlist = py{38,39,310}-{pytest,flake8},mypy

[gh-actions]
python =
2.7: py27
3.8: py38
3.9: py39
3.10: py310, mypy

[testenv]

[testenv:py{27,39}-pytest]
[testenv:py{38,39,310}-pytest]
deps =
-rtest-deps.txt
commands = pytest
passenv = HOME
recreate = False

[testenv:py{27,39}-flake8]
[testenv:py{38,39,310}-flake8]
platform = linux|darwin
deps = flake8
commands = python -m flake8 src
usedevelop = True
recreate = False

[testenv:mypy]
deps = -rtest-deps.txt
commands = mypy src \
--disallow-untyped-calls \
--disallow-untyped-defs \
--disallow-incomplete-defs
recreate = False

0 comments on commit cb331df

Please sign in to comment.