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

Tdl 20778 code refactoring #45

Merged
merged 40 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
eaa1eb6
added pre-commit
somethingmorerelevant Sep 28, 2022
30bfd30
added pre-commit and updated gitignore
somethingmorerelevant Sep 28, 2022
44f6da2
updated file structure
somethingmorerelevant Oct 3, 2022
0c62c08
updated init for tap
somethingmorerelevant Oct 3, 2022
8ecb433
fixed sync.py
somethingmorerelevant Oct 6, 2022
bae0e69
fixed discovery
somethingmorerelevant Oct 6, 2022
f2e9799
fixed streams
somethingmorerelevant Oct 10, 2022
b8019df
removed pendulum dependancy
somethingmorerelevant Oct 11, 2022
7529d9a
added pagination support to bans stream
somethingmorerelevant Oct 12, 2022
76ba0f7
pylint and formatting issues
somethingmorerelevant Oct 13, 2022
3bb5766
Changes:
shantanu73 Oct 13, 2022
9abfd9d
Changes:
shantanu73 Oct 18, 2022
5b71144
removed dependancy of unittest on pendulum library
shantanu73 Oct 18, 2022
ab00310
added typehints and docstrings
somethingmorerelevant Oct 18, 2022
270e013
Merge branch 'TDL_20778_code_refactoring' of github.com:singer-io/tap…
somethingmorerelevant Oct 18, 2022
cd1822b
Changes:
shantanu73 Oct 18, 2022
c0f6db5
added config param for bans stream page size
somethingmorerelevant Nov 3, 2022
3edd865
added warning for 400 exception
somethingmorerelevant Nov 3, 2022
2c2c5cb
fixed schema issues
somethingmorerelevant Nov 3, 2022
9a22a35
added replication method to catalog
somethingmorerelevant Nov 8, 2022
24afc7e
fixed automatic fields issue
somethingmorerelevant Nov 9, 2022
d0b5e4b
fixed discovery changes
somethingmorerelevant Nov 10, 2022
c435e42
fixed pylint issue
somethingmorerelevant Nov 10, 2022
8e2e05c
created classes for each stream
somethingmorerelevant Nov 11, 2022
1796c45
minor enhancements
somethingmorerelevant Nov 11, 2022
39661eb
fixed review comments
somethingmorerelevant Nov 14, 2022
80982d5
fixed discovery changes
somethingmorerelevant Nov 14, 2022
ffa3806
removed duplicate function
somethingmorerelevant Nov 14, 2022
0adfeec
Tdl 18828 add integration tests (#47)
somethingmorerelevant Nov 14, 2022
4273e78
fixed pylint issues
somethingmorerelevant Nov 14, 2022
d4df3f1
Fixed bookmark tests.
shantanu73 Nov 14, 2022
2a1adac
removed singer method from context
somethingmorerelevant Nov 14, 2022
6114d48
fixed naming conventions
somethingmorerelevant Nov 14, 2022
a197834
fixed suggestions on PR
somethingmorerelevant Nov 14, 2022
688ab9d
fixed interupted sync expectations
somethingmorerelevant Nov 15, 2022
6686a94
fixed inter sync
somethingmorerelevant Nov 15, 2022
9fdbc5b
fixed pylint issue
somethingmorerelevant Nov 15, 2022
b7765eb
fixed review comments
somethingmorerelevant Nov 16, 2022
94a0918
fixed linting issues
somethingmorerelevant Nov 16, 2022
1b70322
fixed assert for automatic fields
somethingmorerelevant Nov 16, 2022
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
8 changes: 4 additions & 4 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
(write a short description or paste a link to JIRA)

# Manual QA steps
-
-

# Risks
-
-

# Rollback steps
- revert this branch
31 changes: 10 additions & 21 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,7 @@ coverage.xml
*,cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/
Expand All @@ -72,8 +59,6 @@ target/
# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# dotenv
.env
Expand All @@ -92,11 +77,15 @@ ENV/
._*
.DS_Store

# Custom stuff
env.sh
state.json
catalog.json
config.json
.autoenv.zsh

rsa-key
tags
properties.json

# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
57 changes: 57 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
default_stages: [commit]
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: check-merge-conflict
- id: check-docstring-first
- id: debug-statements
- id: trailing-whitespace
- id: check-toml
- id: end-of-file-fixer
- id: check-yaml
- id: sort-simple-yaml
- id: check-json
- id: pretty-format-json
args: ['--autofix','--no-sort-keys']

- repo: https://github.com/pycqa/isort
rev: 5.10.1
hooks:
- id: isort

- repo: https://github.com/psf/black
rev: 22.8.0
hooks:
- id: black

- repo: https://github.com/pycqa/flake8
rev: 5.0.4
hooks:
- id: flake8
additional_dependencies: [
'flake8-print',
'flake8-debugger',
]

- repo: https://github.com/PyCQA/bandit
rev: '1.7.4'
hooks:
- id: bandit

- repo: https://github.com/asottile/pyupgrade
rev: v2.37.3
hooks:
- id: pyupgrade
args: [--py37-plus]

- repo: https://github.com/PyCQA/docformatter
rev: v1.5.0
hooks:
- id: docformatter
args: [--in-place]

- repo: https://github.com/codespell-project/codespell
rev: v2.2.1
hooks:
- id: codespell
1 change: 0 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -617,4 +617,3 @@ Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

END OF TERMS AND CONDITIONS

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ authorization request), log into your Zendesk Chat / Zopim account, go to
Settings -> Account -> API -> Add API Client

Once you create the API Client you will receive a client ID and client secret.
Use these in conjunction with your chose method of performing the OAuth 2
reqeust to obtain an access token to your (or a third-party) Zendesk Chat /
Use these in conjunction with your choice method of performing the OAuth 2
request to obtain an access token to your (or a third-party) Zendesk Chat /
Zopim account.

3. Create the Config File
Expand Down
4 changes: 4 additions & 0 deletions config.json.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"access_token":"<token_here>",
"start_date":"12/01/2010"
}
21 changes: 21 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[tool.black]
line-length = 120
target-version = ['py37',]
include = '\.pyi?$'

[flake8]
profile = "black"
max-line-length = 120
exclude = "build,.git,.tox,./tests/.env,tests"
ignore = "W504,W601,D203"

[tool.pylint]
max-line-length = 120
disable = ["R0801",]

[tool.isort]
profile = "black"
multi_line_output = 3

[tool.bandit]
exclude_dirs = ["tests",".env"]
8 changes: 8 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
[metadata]
description-file = README.md


[flake8]
ignore = W504,W601,D203
profile = black
max-line-length = 120
exclude = .git,__pycache__,docs/source/conf.py,old,build,dist,.git,.tox,./tests/.env,tests
max-complexity = 10
51 changes: 21 additions & 30 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
#!/usr/bin/env python
from setuptools import setup, find_packages
from setuptools import find_packages, setup

setup(name="tap-zendesk-chat",
version="0.3.2",
description="Singer.io tap for extracting data from the Zendesk Chat API",
author="Stitch",
url="http://singer.io",
classifiers=["Programming Language :: Python :: 3 :: Only"],
py_modules=["tap_zendesk_chat"],
install_requires=[
"python-dateutil==2.6.0", # because of singer-python issue
"pendulum==1.2.0", # because of singer-python issue
"singer-python==5.12.1",
"requests==2.20.0",
],
extras_require={
'dev': [
'pylint==2.7.4',
'ipdb',
'nose'
]
},
entry_points="""
[console_scripts]
tap-zendesk-chat=tap_zendesk_chat:main
""",
packages=["tap_zendesk_chat"],
package_data = {
"schemas": ["tap_zendesk_chat/schemas/*.json"]
},
include_package_data=True,
setup(
name="tap-zendesk-chat",
version="0.3.2",
description="Singer.io tap for extracting data from the Zendesk Chat API",
author="Stitch",
url="https://singer.io",
classifiers=["Programming Language :: Python :: 3 :: Only"],
py_modules=["tap_zendesk_chat"],
install_requires=[
"singer-python==5.12.1",
"requests==2.20.0",
],
extras_require={"dev": ["pylint", "ipdb", "nose"]},
entry_points="""
[console_scripts]
tap-zendesk-chat=tap_zendesk_chat:main
""",
packages=find_packages(exclude=["tests"]),
package_data={"schemas": ["tap_zendesk_chat/schemas/*.json"]},
include_package_data=True,
)
127 changes: 9 additions & 118 deletions tap_zendesk_chat/__init__.py
Original file line number Diff line number Diff line change
@@ -1,134 +1,25 @@
#!/usr/bin/env python3
import os
import singer
from singer import metrics, utils, metadata
from singer.catalog import Catalog, CatalogEntry, Schema
from requests.exceptions import HTTPError
from . import streams as streams_
from singer.utils import handle_top_exception, parse_args

from .context import Context
from .http import Client
from .discover import discover
from .sync import sync

REQUIRED_CONFIG_KEYS = ["start_date", "access_token"]
LOGGER = singer.get_logger()
kethan1122 marked this conversation as resolved.
Show resolved Hide resolved


def get_abs_path(path):
return os.path.join(os.path.dirname(os.path.realpath(__file__)), path)


def load_schema(tap_stream_id):
path = "schemas/{}.json".format(tap_stream_id)
schema = utils.load_json(get_abs_path(path))
dependencies = schema.pop("tap_schema_dependencies", [])
refs = {}
for sub_stream_id in dependencies:
refs[sub_stream_id] = load_schema(sub_stream_id)
if refs:
singer.resolve_schema_references(schema, refs)
return schema


def ensure_credentials_are_authorized(client):
# The request will throw an exception if the credentials are not authorized
client.request(streams_.DEPARTMENTS.tap_stream_id)


def is_account_endpoint_authorized(client):
# The account endpoint is restricted to zopim accounts, meaning integrated
# Zendesk accounts will get a 403 for this endpoint.
try:
client.request(streams_.ACCOUNT.tap_stream_id)
except HTTPError as e:
if e.response.status_code == 403:
LOGGER.info(
"Ignoring 403 from account endpoint - this must be an "
"integrated Zendesk account. This endpoint will be excluded "
"from discovery."
)
return False
else:
raise
return True


def discover(config):
client = Client(config)
ensure_credentials_are_authorized(client)
include_account_stream = is_account_endpoint_authorized(client)
catalog = Catalog([])
for stream in streams_.all_streams:
if (not include_account_stream
and stream.tap_stream_id == streams_.ACCOUNT.tap_stream_id):
continue
raw_schema = load_schema(stream.tap_stream_id)
mdata = build_metadata(raw_schema, stream)
schema = Schema.from_dict(raw_schema)
catalog.streams.append(CatalogEntry(
stream=stream.tap_stream_id,
tap_stream_id=stream.tap_stream_id,
key_properties=stream.pk_fields,
schema=schema,
metadata=metadata.to_list(mdata)
))
return catalog

def build_metadata(raw_schema, stream):

mdata = metadata.new()
metadata.write(mdata, (), 'valid-replication-keys', list(stream.replication_key))
metadata.write(mdata, (), 'table-key-properties', list(stream.pk_fields))
for prop in raw_schema['properties'].keys():
if prop in stream.replication_key or prop in stream.pk_fields:
metadata.write(mdata, ('properties', prop), 'inclusion', 'automatic')
else:
metadata.write(mdata, ('properties', prop), 'inclusion', 'available')

return mdata


def output_schema(stream):
schema = load_schema(stream.tap_stream_id)
singer.write_schema(stream.tap_stream_id, schema, stream.pk_fields)


def is_selected(stream):
mdata = metadata.to_map(stream.metadata)
return metadata.get(mdata, (), 'selected')

def sync(ctx):
currently_syncing = ctx.state.get("currently_syncing")
start_idx = streams_.all_stream_ids.index(currently_syncing) \
if currently_syncing else 0
stream_ids_to_sync = [cs.tap_stream_id for cs in ctx.catalog.streams
if is_selected(cs)]
streams = [s for s in streams_.all_streams[start_idx:]
if s.tap_stream_id in stream_ids_to_sync]
for stream in streams:
ctx.state["currently_syncing"] = stream.tap_stream_id
output_schema(stream)
ctx.write_state()
stream.sync(ctx)
ctx.state["currently_syncing"] = None
ctx.write_state()


def main_impl():
args = utils.parse_args(REQUIRED_CONFIG_KEYS)
@handle_top_exception(LOGGER)
def main():
"""performs sync and discovery."""
args = parse_args(REQUIRED_CONFIG_KEYS)
if args.discover:
discover(args.config).dump()
print()
else:
catalog = Catalog.from_dict(args.properties) \
if args.properties else discover(args.config)
ctx = Context(args.config, args.state, catalog)
ctx = Context(args.config, args.state, args.catalog or discover(args.config))
sync(ctx)

def main():
try:
main_impl()
except Exception as exc:
LOGGER.critical(exc)
raise exc

if __name__ == "__main__":
main()
Loading