Skip to content

Commit

Permalink
Fix files
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarrmondragon committed Feb 14, 2023
1 parent e18a77c commit 2b569b5
Show file tree
Hide file tree
Showing 15 changed files with 219 additions and 142 deletions.
1 change: 1 addition & 0 deletions .github/workflows/cookiecutter-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches: [main]
paths: ["cookiecutter/**", "e2e-tests/cookiecutters/**"]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
Expand Down
6 changes: 0 additions & 6 deletions cookiecutter/tap-template/{{cookiecutter.tap_id}}/mypy.ini

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ requests = "^2.28.2"
[tool.poetry.group.dev.dependencies]
pytest = "^7.2.1"
flake8 = "^5.0.4"
darglint = "^1.8.1"
black = "^23.1.0"
pydocstyle = "^6.3.0"
pyupgrade = "^3.3.1"
mypy = "^1.0.0"
isort = "^5.11.5"
{%- if cookiecutter.stream_type in ["REST", "GraphQL"] %}
Expand All @@ -46,6 +47,10 @@ profile = "black"
multi_line_output = 3 # Vertical Hanging Indent
src_paths = "{{cookiecutter.library_name}}"

[tool.mypy]
python_version = "3.9"
warn_unused_configs = true

[build-system]
requires = ["poetry-core>=1.0.8"]
build-backend = "poetry.core.masonry.api"
Expand Down
2 changes: 1 addition & 1 deletion cookiecutter/tap-template/{{cookiecutter.tap_id}}/tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ commands =
poetry run black --check --diff {{cookiecutter.library_name}}/
poetry run isort --check {{cookiecutter.library_name}}
poetry run flake8 {{cookiecutter.library_name}}
poetry run pydocstyle {{cookiecutter.library_name}}
# refer to mypy.ini for specific settings
poetry run mypy {{cookiecutter.library_name}} --exclude='{{cookiecutter.library_name}}/tests'

[flake8]
docstring-convention = google
ignore = W503
max-line-length = 88
max-complexity = 10
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"""Tap for {{ cookiecutter.source_name }}."""
"""Tap for {{ cookiecutter.source_name }}."""
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
"""{{ cookiecutter.source_name }} tap class."""

from typing import List
from __future__ import annotations

from singer_sdk import {{ 'SQL' if cookiecutter.stream_type == 'SQL' else '' }}Tap, {{ 'SQL' if cookiecutter.stream_type == 'SQL' else '' }}Stream
from singer_sdk import {{ 'SQL' if cookiecutter.stream_type == 'SQL' else '' }}Tap
from singer_sdk import typing as th # JSON schema typing helpers

{%- if cookiecutter.stream_type == "SQL" %}

from {{ cookiecutter.library_name }}.client import {{ cookiecutter.source_name }}Stream
{%- else %}
# TODO: Import your custom stream types here:
from {{ cookiecutter.library_name }}.streams import (
{{ cookiecutter.source_name }}Stream,
{%- if cookiecutter.stream_type in ("GraphQL", "REST", "Other") %}
UsersStream,
GroupsStream,
{%- endif %}
)
{%- endif %}

{%- if cookiecutter.stream_type in ("GraphQL", "REST", "Other") %}
# TODO: Compile a list of custom stream types here
# OR rewrite discover_streams() below with your custom logic.
STREAM_TYPES = [
{{ cookiecutter.source_name }}Stream,
UsersStream,
GroupsStream,
]
# TODO: Import your custom stream types here:
from {{ cookiecutter.library_name }} import streams
{%- endif %}


Expand All @@ -41,31 +27,38 @@ class Tap{{ cookiecutter.source_name }}({{ 'SQL' if cookiecutter.stream_type ==
th.StringType,
required=True,
secret=True, # Flag config as protected.
description="The token to authenticate against the API service"
description="The token to authenticate against the API service",
),
th.Property(
"project_ids",
th.ArrayType(th.StringType),
required=True,
description="Project IDs to replicate"
description="Project IDs to replicate",
),
th.Property(
"start_date",
th.DateTimeType,
description="The earliest record date to sync"
description="The earliest record date to sync",
),
th.Property(
"api_url",
th.StringType,
default="https://api.mysample.com",
description="The url for the API service"
description="The url for the API service",
),
).to_dict()
{%- if cookiecutter.stream_type in ("GraphQL", "REST", "Other") %}

def discover_streams(self) -> List[Stream]:
"""Return a list of discovered streams."""
return [stream_class(tap=self) for stream_class in STREAM_TYPES]
def discover_streams(self) -> list[streams.{{ cookiecutter.source_name }}Stream]:
"""Return a list of discovered streams.
Returns:
A list of discovered streams.
"""
return [
streams.GroupsStream(self),
streams.UsersStream(self),
]
{%- endif %}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
"""GraphQL client handling, including {{ cookiecutter.source_name }}Stream base class."""

import requests
from pathlib import Path
from typing import Any, Dict, Optional, Union, List, Iterable
from __future__ import annotations

from typing import Iterable

import requests
from singer_sdk.streams import {{ cookiecutter.stream_type }}Stream

{%- if cookiecutter.auth_method in ("OAuth2", "JWT") %}

from {{ cookiecutter.library_name }}.auth import {{ cookiecutter.source_name }}Authenticator
{%- endif %}

Expand All @@ -16,7 +19,11 @@ class {{ cookiecutter.source_name }}Stream({{ cookiecutter.stream_type }}Stream)
# TODO: Set the API's base URL here:
@property
def url_base(self) -> str:
"""Return the API URL root, configurable via tap settings."""
"""Return the API URL root, configurable via tap settings.

Returns:
The base URL for all requests.
"""
return self.config["api_url"]

# Alternatively, use a static string for url_base:
Expand All @@ -25,14 +32,22 @@ class {{ cookiecutter.source_name }}Stream({{ cookiecutter.stream_type }}Stream)
{%- if cookiecutter.auth_method in ("OAuth2", "JWT") %}
@property
def authenticator(self) -> {{ cookiecutter.source_name }}Authenticator:
"""Return a new authenticator object."""
"""Return a new authenticator object.

Returns:
An authenticator instance.
"""
return {{ cookiecutter.source_name }}Authenticator.create_for_stream(self)

{%- endif %}

@property
def http_headers(self) -> dict:
"""Return the http headers needed."""
"""Return the http headers needed.

Returns:
A dictionary of HTTP headers.
"""
headers = {}
if "user_agent" in self.config:
headers["User-Agent"] = self.config.get("user_agent")
Expand All @@ -43,13 +58,28 @@ class {{ cookiecutter.source_name }}Stream({{ cookiecutter.stream_type }}Stream)
return headers

def parse_response(self, response: requests.Response) -> Iterable[dict]:
"""Parse the response and return an iterator of result records."""
"""Parse the response and return an iterator of result records.

Args:
response: The HTTP ``requests.Response`` object.

Yields:
Each record from the source.
"""
# TODO: Parse response body and return a set of records.
resp_json = response.json()
for record in resp_json.get("<TODO>"):
yield record

def post_process(self, row: dict, context: Optional[dict] = None) -> Optional[dict]:
"""As needed, append or transform raw data to match expected structure."""
def post_process(self, row: dict, context: dict | None = None) -> dict | None:
"""As needed, append or transform raw data to match expected structure.

Args:
row: An individual record from the stream.
context: The stream context.

Returns:
The updated record dictionary, or ``None`` to skip the record.
"""
# TODO: Delete this method if not needed.
return row
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
"""Custom client handling, including {{ cookiecutter.source_name }}Stream base class."""

from __future__ import annotations

import requests
from pathlib import Path
from typing import Any, Dict, Optional, Union, List, Iterable
from typing import Any, Iterable

from singer_sdk.streams import Stream


class {{ cookiecutter.source_name }}Stream(Stream):
"""Stream class for {{ cookiecutter.source_name }} streams."""

def get_records(self, context: Optional[dict]) -> Iterable[dict]:
def get_records(self, context: dict | None) -> Iterable[dict]:
"""Return a generator of record-type dictionary objects.

The optional `context` argument is used to identify a specific slice of the
Expand Down
Loading

0 comments on commit 2b569b5

Please sign in to comment.