Skip to content

Commit

Permalink
feat: add JSON Schema Property helpers for allowed_values (enum
Browse files Browse the repository at this point in the history
…) and `examples` (#1098)

* chore: initial refactor for readability

* feat: add Meltano rendering logic in private helper module

* feat: add `secret=True` support in JSON Schema type helpers

* change: update examples to use 'secret=True' for protected settings

* chore: flake8 fix

* add unit tests for type helpers

* fix missing secret flag on unit test

* chore: get tests passing

* chore: add test for description

* chore: remove commented code

* chore: remove files related to #1094

* chore: revert --about updates

* use constants for annotation keys

* chore: bump validator to Draft7

* chore: add testing for is_secret_type

* chore: add tests

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* chore: more tests

* docs: add info to FAQ

* chore: add test for integer type

* feat: add `allowed_values` and `examples` to Property class

* chore: add tests and samples

* chore: fix missing typing import

* docs: updated usage examples in typing module ref

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
aaronsteers and pre-commit-ci[bot] authored Oct 24, 2022
1 parent 6cdb0fd commit 6607487
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 7 deletions.
4 changes: 3 additions & 1 deletion samples/sample_tap_google_analytics/ga_tap.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ class SampleTapGoogleAnalytics(Tap):
name: str = "sample-tap-google-analytics"
config_jsonschema = PropertiesList(
Property("view_id", StringType(), required=True),
Property("client_email", StringType(), required=True),
Property(
"client_email", StringType(), required=True, examples=["[email protected]"]
),
Property("private_key", StringType(), required=True, secret=True),
).to_dict()

Expand Down
1 change: 1 addition & 0 deletions samples/sample_tap_sqlite/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class SQLiteTap(SQLTap):
DB_PATH_CONFIG,
th.StringType,
description="The path to your SQLite database file(s).",
examples=["./path/to/my.db", "/absolute/path/to/my.db"],
)
).to_dict()

Expand Down
28 changes: 22 additions & 6 deletions singer_sdk/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@
.. code-block:: python
jsonschema = PropertiesList(
Property("username", StringType, required=True),
Property("password", StringType, required=True, secret=True),
Property("id", IntegerType, required=True),
Property("name", StringType),
Property("tags", ArrayType(StringType)),
Property("ratio", NumberType),
Property("foo_or_bar", StringType, allowed_values=["foo", "bar"]),
Property("ratio", NumberType, examples=[0.25, 0.75, 1.0]),
Property("days_active", IntegerType),
Property("updated_on", DateTimeType),
Property("is_deleted", BooleanType),
Property(
"author",
ObjectType(
Property("id", StringType),
Property("name", StringType),
)
),
Property("tags", ArrayType(StringType)),
Property(
"groups",
ArrayType(
Expand All @@ -42,7 +46,7 @@
from __future__ import annotations

import sys
from typing import Generic, Mapping, TypeVar, Union, cast
from typing import Any, Generic, Mapping, TypeVar, Union, cast

import sqlalchemy
from jsonschema import validators
Expand Down Expand Up @@ -356,8 +360,10 @@ def __init__(
wrapped: W | type[W],
required: bool = False,
default: _JsonValue = None,
description: str = None,
secret: bool = False,
description: str | None = None,
secret: bool | None = False,
allowed_values: list[Any] | None = None,
examples: list[Any] | None = None,
) -> None:
"""Initialize Property object.
Expand All @@ -374,13 +380,19 @@ def __init__(
default: Default value in the JSON Schema.
description: Long-text property description.
secret: True if this is a credential or other secret.
allowed_values: A list of allowed value options, if only specific values
are permitted. This will define the type as an 'enum'.
examples: Optional. A list of one or more sample values. These may be
displayed to the user as hints of the expected format of inputs.
"""
self.name = name
self.wrapped = wrapped
self.optional = not required
self.default = default
self.description = description
self.secret = secret
self.allowed_values = allowed_values or None
self.examples = examples or None

@property
def type_dict(self) -> dict: # type: ignore # OK: @classproperty vs @property
Expand Down Expand Up @@ -423,6 +435,10 @@ def to_dict(self) -> dict:
JSONSCHEMA_ANNOTATION_WRITEONLY: True,
}
)
if self.allowed_values:
type_dict.update({"enum": self.allowed_values})
if self.examples:
type_dict.update({"examples": self.examples})
return {self.name: type_dict}


Expand Down
16 changes: 16 additions & 0 deletions tests/core/test_jsonschema_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,22 @@ def test_inbuilt_type(json_type: JSONTypeHelper, expected_json_schema: dict):
},
{is_integer_type},
),
(
Property(
"my_prop9",
IntegerType,
allowed_values=[1, 2, 3, 4, 5, 6, 7, 8, 9],
examples=[1, 2, 3],
),
{
"my_prop9": {
"type": ["integer", "null"],
"enum": [1, 2, 3, 4, 5, 6, 7, 8, 9],
"examples": [1, 2, 3],
}
},
{is_integer_type},
),
],
)
def test_property_creation(
Expand Down

0 comments on commit 6607487

Please sign in to comment.