Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Nested settings are now documented in the output of --about --format=markdown #2263

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 61 additions & 22 deletions singer_sdk/about.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,60 @@ def format_about(self, about_info: AboutInfo) -> str:
class MarkdownFormatter(AboutFormatter, format_name="markdown"):
"""About formatter for Markdown output."""

def _generate_property_row(
self,
name: str,
schema: dict[str, t.Any],
*,
required: bool,
parent_name: str | None = None,
) -> t.Generator[str, None, None]:
"""Generate a row for this property and for nested properties, if any.

Args:
name: The property name.
schema: The property schema.
required: Whether the property is required to be present.
parent_name: The parent property name, if any.

Yields:
One markdown table row for the setting, and one for each sub-property.
"""
setting_name = f"{parent_name}.{name}" if parent_name else name
md_description = schema.get("description", "").replace("\n", "<BR/>")
yield (
f"| {setting_name} "
f"| {'True' if required else 'False':8} "
f"| {schema.get('default', 'None'):7} "
f"| {md_description:11} |"
)
if "properties" in schema:
yield from self._generate_property_rows(schema, parent_name=setting_name)

def _generate_property_rows(
self,
schema: dict[str, t.Any],
*,
parent_name: str = "",
) -> t.Generator[str, None, None]:
"""Generate a row for each property in the schema.

Args:
schema: A JSON object schema.
parent_name: The parent property name, if any.

Yields:
One markdown table row for each property.
"""
required_settings = schema.get("required", [])
for name, sub_schema in schema.get("properties", {}).items():
yield from self._generate_property_row(
name,
sub_schema,
required=name in required_settings,
parent_name=parent_name,
)

def format_about(self, about_info: AboutInfo) -> str:
"""Render about information.

Expand All @@ -173,18 +227,8 @@ def format_about(self, about_info: AboutInfo) -> str:
Returns:
A formatted string.
"""
max_setting_len = max(len(k) for k in about_info.settings["properties"])

# Set table base for markdown
table_base = (
f"| {'Setting':{max_setting_len}}| Required | Default | Description |\n"
f"|:{'-' * max_setting_len}|:--------:|:-------:|:------------|\n"
)

# Empty list for string parts
md_list = []
# Get required settings for table
required_settings = about_info.settings.get("required", [])

# Iterate over Dict to set md
md_list.append(
Expand All @@ -201,19 +245,14 @@ def format_about(self, about_info: AboutInfo) -> str:
md_list.append(capabilities)

setting = "## Settings\n\n"

for k, v in about_info.settings.get("properties", {}).items():
md_description = v.get("description", "").replace("\n", "<BR/>")
table_base += (
f"| {k}{' ' * (max_setting_len - len(k))}"
f"| {'True' if k in required_settings else 'False':8} | "
f"{v.get('default', 'None'):7} | "
f"{md_description:11} |\n"
)

setting += table_base
settings_table = (
"| Setting | Required | Default | Description |\n"
"|:--------|:--------:|:-------:|:------------|\n"
)
settings_table += "\n".join(self._generate_property_rows(about_info.settings))
setting += settings_table
setting += (
"\n"
"\n\n"
+ "\n".join(
[
"A full list of supported settings and capabilities "
Expand Down
10 changes: 10 additions & 0 deletions tests/core/test_about.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ def about_info() -> AboutInfo:
"type": "string",
"description": "API key for the tap to use.",
},
"complex_setting": {
"type": "object",
"description": "A complex setting, with sub-settings.",
"properties": {
"sub_setting": {
"type": "string",
"description": "A sub-setting.",
}
},
},
},
"required": ["api_key"],
},
Expand Down
10 changes: 10 additions & 0 deletions tests/snapshots/about_format/json.snap.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@
"api_key": {
"type": "string",
"description": "API key for the tap to use."
},
"complex_setting": {
"type": "object",
"description": "A complex setting, with sub-settings.",
"properties": {
"sub_setting": {
"type": "string",
"description": "A sub-setting."
}
}
}
},
"required": [
Expand Down
10 changes: 6 additions & 4 deletions tests/snapshots/about_format/markdown.snap.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ Built with the [Meltano Singer SDK](https://sdk.meltano.com).

## Settings

| Setting | Required | Default | Description |
|:----------|:--------:|:-------:|:------------|
| start_date| False | None | Start date for the tap to extract data from. |
| api_key | True | None | API key for the tap to use. |
| Setting | Required | Default | Description |
|:--------|:--------:|:-------:|:------------|
| start_date | False | None | Start date for the tap to extract data from. |
| api_key | True | None | API key for the tap to use. |
| complex_setting | False | None | A complex setting, with sub-settings. |
| complex_setting.sub_setting | False | None | A sub-setting. |

A full list of supported settings and capabilities is available by running: `tap-example --about`

Expand Down
2 changes: 1 addition & 1 deletion tests/snapshots/about_format/text.snap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ Version: 0.1.1
SDK Version: 1.0.0
Supported Python Versions: ['3.6', '3.7', '3.8']
Capabilities: [catalog, discover, state]
Settings: {'properties': {'start_date': {'type': 'string', 'format': 'date-time', 'description': 'Start date for the tap to extract data from.'}, 'api_key': {'type': 'string', 'description': 'API key for the tap to use.'}}, 'required': ['api_key']}
Settings: {'properties': {'start_date': {'type': 'string', 'format': 'date-time', 'description': 'Start date for the tap to extract data from.'}, 'api_key': {'type': 'string', 'description': 'API key for the tap to use.'}, 'complex_setting': {'type': 'object', 'description': 'A complex setting, with sub-settings.', 'properties': {'sub_setting': {'type': 'string', 'description': 'A sub-setting.'}}}}, 'required': ['api_key']}