Skip to content

Commit bdcc947

Browse files
committed
add better exceptions for broken spec files
1 parent b29d914 commit bdcc947

File tree

3 files changed

+92
-59
lines changed

3 files changed

+92
-59
lines changed

dlt_init_openapi/cli/__init__.py

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from dlt_init_openapi.cli.cli_endpoint_selection import questionary_endpoint_selection
1111
from dlt_init_openapi.config import Config
12+
from dlt_init_openapi.exceptions import DltOpenAPITerminalException
1213
from dlt_init_openapi.utils import update_rest_api
1314

1415
app = typer.Typer(add_completion=False)
@@ -91,31 +92,38 @@ def _init_command_wrapped(
9192
typer.secho("Provide either --url or --path, not both", fg=typer.colors.RED)
9293
raise typer.Exit(code=1)
9394

94-
# synch rest api
95-
update_rest_api.update_rest_api(force=update_rest_api_source)
96-
97-
config = _load_config(
98-
path=config_path,
99-
config={
100-
"project_name": source,
101-
"package_name": source,
102-
"output_path": output_path,
103-
"endpoint_filter": questionary_endpoint_selection if interactive else None,
104-
"global_limit": global_limit,
105-
},
106-
)
107-
108-
if config.project_dir.exists():
109-
if not questionary.confirm(
110-
f"Directory {config.project_dir} exists, do you want to continue and update the generated files? "
111-
+ "This will overwrite your changes in those files."
112-
).ask():
113-
logger.warning("Exiting...")
114-
exit(0)
115-
116-
create_new_client(
117-
url=url,
118-
path=path,
119-
config=config,
120-
)
121-
logger.success("Pipeline created. Learn more at https://dlthub.com/docs. See you next time :)")
95+
try:
96+
97+
# synch rest api
98+
update_rest_api.update_rest_api(force=update_rest_api_source)
99+
100+
config = _load_config(
101+
path=config_path,
102+
config={
103+
"project_name": source,
104+
"package_name": source,
105+
"output_path": output_path,
106+
"endpoint_filter": questionary_endpoint_selection if interactive else None,
107+
"global_limit": global_limit,
108+
},
109+
)
110+
111+
if config.project_dir.exists():
112+
if not questionary.confirm(
113+
f"Directory {config.project_dir} exists, do you want to continue and update the generated files? "
114+
+ "This will overwrite your changes in those files."
115+
).ask():
116+
logger.warning("Exiting...")
117+
exit(0)
118+
119+
create_new_client(
120+
url=url,
121+
path=path,
122+
config=config,
123+
)
124+
logger.success("Pipeline created. Learn more at https://dlthub.com/docs. See you next time :)")
125+
126+
except DltOpenAPITerminalException as exc:
127+
logger.error("Encountered terminal exception:")
128+
logger.error(exc)
129+
logger.info("Exiting...")

dlt_init_openapi/exceptions.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,38 @@
11
class DltOpenAPIException(Exception):
22
pass
3+
4+
5+
class DltOpenAPITerminalException(DltOpenAPIException):
6+
pass
7+
8+
9+
class DltOpenAPINot30Exception(DltOpenAPITerminalException):
10+
def __init__(self, swagger_detected: bool = False) -> None:
11+
12+
swagger_helper = "If this is a Swagger/OpenAPI 2.0 or earlier spec, "
13+
if swagger_detected:
14+
swagger_helper = "It looks like this is a Swagger/OpenAPI 2.0 spec, "
15+
16+
convert_helper = (
17+
"you can convert it to an openapi 3.0 spec by going to https://editor.swagger.io/, "
18+
+ "pasting your spec and selecting 'Edit' -> 'Convert to OpenAPI 3.0' from the Menu "
19+
+ "and then retry with the converted file."
20+
)
21+
22+
super().__init__(
23+
"The spec you selected does not appear to be an OpenAPI 3.0 spec. " + swagger_helper + convert_helper
24+
)
25+
26+
27+
class DltInvalidSpecException(DltOpenAPITerminalException):
28+
def __init__(self) -> None:
29+
30+
super().__init__(
31+
"Could not validate selected spec, please provide a valid YAML or JSON OpenAPI 3.0 or higher spec."
32+
)
33+
34+
35+
class DltUnparseableSpecException(DltOpenAPITerminalException):
36+
def __init__(self) -> None:
37+
38+
super().__init__("Could not parse selected spec, please provide a valid YAML or JSON document.")

dlt_init_openapi/parser/openapi_parser.py

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from loguru import logger
88
from yaml import BaseLoader
99

10-
from dlt_init_openapi.exceptions import DltOpenAPIException
10+
from dlt_init_openapi.exceptions import DltInvalidSpecException, DltOpenAPINot30Exception, DltUnparseableSpecException
1111
from dlt_init_openapi.parser.config import Config
1212
from dlt_init_openapi.parser.context import OpenapiContext
1313
from dlt_init_openapi.parser.endpoints import EndpointCollection
@@ -39,30 +39,17 @@ def parse(self, data: bytes) -> None:
3939
try:
4040
spec = osp.OpenAPI.parse_obj(self.spec_raw)
4141
except Exception as e:
42-
raise DltOpenAPIException("Could not Validate spec:\n" + str(e)) from e
42+
raise DltInvalidSpecException() from e
4343
logger.success("Spec validation successful")
4444

4545
# check if this is openapi 3.0
46-
convert_info = (
47-
"you can convert it to an openapi 3.0 spec by going to https://editor.swagger.io/, "
48-
+ "pasting your spec and selecting 'Edit' -> 'Convert to OpenAPI 3.0' from the Menu "
49-
+ "and then retry with the converted file."
50-
)
5146
swagger_version = self.spec_raw.get("swagger")
5247
if swagger_version:
53-
logger.error(
54-
"The spec you selected appears to be a Swagger/OpenAPI version 2 spec or older, " + convert_info
55-
)
56-
exit(0)
48+
raise DltOpenAPINot30Exception(swagger_detected=True)
5749

5850
openapi_version = self.spec_raw.get("openapi")
5951
if not openapi_version or not openapi_version.startswith("3"):
60-
logger.error(
61-
"The spec you selected does not appear to be an OpenAPI 3.0 spec. "
62-
+ "If this is a a Swagger/OpenAPI version 2 spec or older, "
63-
+ convert_info
64-
)
65-
exit(1)
52+
raise DltOpenAPINot30Exception(swagger_detected=False)
6653

6754
logger.info("Extracting openapi metadata")
6855
self.context = OpenapiContext(self.config, spec, self.spec_raw)
@@ -88,19 +75,21 @@ def parse(self, data: bytes) -> None:
8875

8976
def _load_yaml_or_json(self, data: bytes) -> Dict[str, Any]:
9077
logger.info("Trying to parse spec as JSON")
91-
92-
data_size = sys.getsizeof(data)
93-
if data_size > 1000000:
94-
mb = round(data_size / 1000000)
95-
logger.warning(f"Spec is around {mb} mb, so parsing might take a while.")
9678
try:
97-
result = json.loads(data.decode())
98-
logger.success("Parsed spec as JSON")
79+
data_size = sys.getsizeof(data)
80+
if data_size > 1000000:
81+
mb = round(data_size / 1000000)
82+
logger.warning(f"Spec is around {mb} mb, so parsing might take a while.")
83+
try:
84+
result = json.loads(data.decode())
85+
logger.success("Parsed spec as JSON")
86+
return result
87+
except ValueError:
88+
logger.info("No valid JSON found")
89+
pass
90+
logger.info("Trying to parse spec as YAML")
91+
result = yaml.load(data, Loader=BaseLoader)
92+
logger.success("Parsed spec as YAML")
9993
return result
100-
except ValueError:
101-
logger.info("No valid JSON found")
102-
pass
103-
logger.info("Trying to parse spec as YAML")
104-
result = yaml.load(data, Loader=BaseLoader)
105-
logger.success("Parsed spec as YAML")
106-
return result
94+
except Exception as exc:
95+
raise DltUnparseableSpecException() from exc

0 commit comments

Comments
 (0)