Update metadata validation logic (issue #924) (#1463)

* Validate metadata with attr

* Update and add tests

* Add check if file exists and update tests

* Format code and update validate metadata

* Revert changes to is_metadata_file()

* Remove format error: whitespaces

* Format test files

Co-authored-by: Anna Scholtz <anna@scholtzan.net>
This commit is contained in:
Linh Nguyen 2020-10-20 16:03:50 -07:00 коммит произвёл GitHub
Родитель 188f0ae5fd
Коммит 2a1454c309
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 74 добавлений и 30 удалений

Просмотреть файл

@ -3,23 +3,54 @@
import re
import yaml
import os
import attr
from typing import List, Optional, Dict
from bigquery_etl.query_scheduling.utils import is_email
METADATA_FILE = "metadata.yaml"
@attr.s(auto_attribs=True)
class Metadata:
"""Representation of metadata file content."""
"""
Representation of a Metadata configuration.
def __init__(
self, friendly_name=None, description=None, owners=[], labels={}, scheduling={}
):
"""Create a new Metadata instance."""
self.friendly_name = friendly_name
self.description = description
self.labels = labels
self.scheduling = scheduling
self.owners = owners
Uses attrs to simplify the class definition and provide validation.
Docs: https://www.attrs.org
"""
friendly_name: str = attr.ib()
description: str = attr.ib()
owners: List[str] = attr.ib()
labels: Dict = attr.ib({})
scheduling: Optional[Dict] = attr.ib({})
@owners.validator
def validate_owners(self, attribute, value):
"""Check that provided email addresses for owners are valid."""
if not all(map(lambda e: is_email(e), value)):
raise ValueError(f"Invalid email for owners: {value}.")
@labels.validator
def validate_labels(self, attribute, value):
"""Check that labels are valid."""
for key, label in value.items():
if not isinstance(label, bool):
if not Metadata.is_valid_label(str(key)):
raise ValueError(
f"""Invalid label key format: {key}.
Key cannot be empty. Only hyphens(-), underscores(_),
lowercase characters, and numbers are allowed.
International characters are not allowed."""
)
elif not Metadata.is_valid_label(str(label)) and not label == "":
raise ValueError(
f"""Invalid label value format: {label}.
Value be empty. Only hyphens(-), underscores(_),
lowercase characters, and numbers are allowed.
International characters are not allowed."""
)
@staticmethod
def is_valid_label(label):
@ -78,27 +109,13 @@ class Metadata:
labels = {}
for key, label in metadata["labels"].items():
if isinstance(label, bool) and Metadata.is_valid_label(
str(key)
):
if isinstance(label, bool):
# publish key-value pair with bool value as tag
if label:
labels[str(key)] = ""
elif Metadata.is_valid_label(
str(key)
) and Metadata.is_valid_label(str(label)):
else:
# all other pairs get published as key-value pair label
labels[str(key)] = str(label)
else:
print(
"""
Invalid label format: {}: {}. Only hyphens (-),
underscores (_), lowercase characters, and numbers
are allowed. International characters are not allowed.
""".format(
key, label
)
)
if "scheduling" in metadata:
scheduling = metadata["scheduling"]

Просмотреть файл

@ -7,8 +7,6 @@ labels:
public_json: true
incremental: true
incremental_export: true
invalid.label: foo
invalid_value: Fo.
1232341234: valid
1234_abcd: valid
number_value: 1234234

Просмотреть файл

@ -7,6 +7,37 @@ TEST_DIR = Path(__file__).parent.parent
class TestParseMetadata(object):
def test_metadata_instantiation(self):
metadata = Metadata(
"Test metadata", "test description", ["test@example.org"], {}
)
assert metadata.friendly_name == "Test metadata"
assert metadata.description == "test description"
assert metadata.owners == ["test@example.org"]
assert metadata.labels == {}
assert metadata.scheduling == {}
def test_invalid_owners(self):
with pytest.raises(ValueError):
Metadata("Test metadata", "test description", ["testexample.org"])
def test_invalid_label(self):
with pytest.raises(ValueError):
Metadata(
"Test metadata",
"test description",
["test@example.org"],
{"INVALID-KEY": "foo"},
)
with pytest.raises(ValueError):
Metadata(
"Test metadata",
"test description",
["test@example.org"],
{"foo": "INVALID-VALUE"},
)
def test_is_valid_label(self):
assert Metadata.is_valid_label("valid_label")
assert Metadata.is_valid_label("valid-label1")
@ -33,8 +64,6 @@ class TestParseMetadata(object):
assert metadata.is_incremental()
assert metadata.is_incremental_export()
assert metadata.review_bug() is None
assert "invalid_value" not in metadata.labels
assert "invalid.label" not in metadata.labels
assert "1232341234" in metadata.labels
assert "1234_abcd" in metadata.labels
assert "number_value" in metadata.labels