Skip to content
Open
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
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
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -154,5 +154,3 @@ singer-check-tap-data
node_modules
generate-schema.js
package-lock.json


53 changes: 53 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
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
args: ["--ignore=W503,E501,C901"]
additional_dependencies: [
'flake8-print',
'flake8-debugger',
]

- 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
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"python.pythonPath": "/Users/jeff.huth/.virtualenvs/tap-asana/bin/python"
}
"python.pythonPath": "/Users/jeff.huth/.virtualenvs/tap-asana/bin/python"
}
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@

## 1.0.1
* Added custom_fields and tags to tasks schema

## 1.0.0
* Releasing from Beta --> GA

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

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 = 100
disable = ["R0801",]

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

[tool.bandit]
exclude_dirs = ["tests",".env"]
20 changes: 3 additions & 17 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,13 @@
url="http://github.com/singer-io/tap-asana",
classifiers=["Programming Language :: Python :: 3 :: Only"],
py_modules=["tap_asana"],
install_requires=[
"asana==0.10.2",
'singer-python==5.12.2'
],
extras_require={
'test': [
'pylint',
'requests==2.20.0',
'nose'
],
'dev': [
'ipdb'
]
},
install_requires=["asana==0.10.2", "singer-python==5.12.2"],
extras_require={"test": ["pylint", "requests==2.20.0", "nose"], "dev": ["ipdb"]},
entry_points="""
[console_scripts]
tap-asana=tap_asana:main
""",
packages=["tap_asana"],
package_data = {
"schemas": ["tap_asana/schemas/*.json"]
},
package_data={"schemas": ["tap_asana/schemas/*.json"]},
include_package_data=True,
)
104 changes: 47 additions & 57 deletions tap_asana/__init__.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
#!/usr/bin/env python3
import os
import datetime
import json
import time
import math
import functools
import asana
import os

import singer
from singer import utils
from singer import metadata
from singer import Transformer
from singer import Transformer, metadata, utils

# Load stream objects into Context
import tap_asana.streams # noqa
from tap_asana.asana import Asana
from tap_asana.context import Context
import tap_asana.streams # Load stream objects into Context

REQUIRED_CONFIG_KEYS = [
"start_date",
"client_id",
"client_secret",
"redirect_uri",
"refresh_token"
"refresh_token",
]


Expand All @@ -36,10 +32,10 @@ def load_schemas():

# This schema represents many of the currency values as JSON schema
# 'number's, which may result in lost precision.
for filename in os.listdir(get_abs_path('schemas')):
path = get_abs_path('schemas') + '/' + filename
schema_name = filename.replace('.json', '')
with open(path) as file: # pylint: disable=unspecified-encoding
for filename in os.listdir(get_abs_path("schemas")):
path = get_abs_path("schemas") + "/" + filename
schema_name = filename.replace(".json", "")
with open(path) as file: # pylint: disable=unspecified-encoding
try:
schemas[schema_name] = json.load(file)
except ValueError:
Expand All @@ -50,17 +46,17 @@ def load_schemas():

def get_discovery_metadata(stream, schema):
mdata = metadata.new()
mdata = metadata.write(mdata, (), 'table-key-properties', stream.key_properties)
mdata = metadata.write(mdata, (), 'forced-replication-method', stream.replication_method)
mdata = metadata.write(mdata, (), "table-key-properties", stream.key_properties)
mdata = metadata.write(mdata, (), "forced-replication-method", stream.replication_method)

if stream.replication_key:
mdata = metadata.write(mdata, (), 'valid-replication-keys', [stream.replication_key])
mdata = metadata.write(mdata, (), "valid-replication-keys", [stream.replication_key])

for field_name in schema['properties'].keys():
for field_name in schema["properties"].keys():
if field_name in stream.key_properties or field_name == stream.replication_key:
mdata = metadata.write(mdata, ('properties', field_name), 'inclusion', 'automatic')
mdata = metadata.write(mdata, ("properties", field_name), "inclusion", "automatic")
else:
mdata = metadata.write(mdata, ('properties', field_name), 'inclusion', 'available')
mdata = metadata.write(mdata, ("properties", field_name), "inclusion", "available")

return metadata.to_list(mdata)

Expand All @@ -80,26 +76,24 @@ def discover():

# create and add catalog entry
catalog_entry = {
'stream': schema_name,
'tap_stream_id': schema_name,
'schema': singer.resolve_schema_references(schema, refs),
'metadata' : get_discovery_metadata(stream, schema),
'key_properties': stream.key_properties,
'replication_key': stream.replication_key,
'replication_method': stream.replication_method
"stream": schema_name,
"tap_stream_id": schema_name,
"schema": singer.resolve_schema_references(schema, refs),
"metadata": get_discovery_metadata(stream, schema),
"key_properties": stream.key_properties,
"replication_key": stream.replication_key,
"replication_method": stream.replication_method,
}
streams.append(catalog_entry)

LOGGER.info("Finished discover")

return {'streams': streams}
return {"streams": streams}


def shuffle_streams(stream_name):
'''
Takes the name of the first stream to sync and reshuffles the order
of the list to put it at the top
'''
"""Takes the name of the first stream to sync and reshuffles the order of
the list to put it at the top."""
matching_index = 0
for i, catalog_entry in enumerate(Context.catalog["streams"]):
if catalog_entry["tap_stream_id"] == stream_name:
Expand All @@ -113,44 +107,40 @@ def sync():
# Emit all schemas first so we have them for child streams
for stream in Context.catalog["streams"]:
if Context.is_selected(stream["tap_stream_id"]):
singer.write_schema(stream["tap_stream_id"],
stream["schema"],
stream["key_properties"])
singer.write_schema(stream["tap_stream_id"], stream["schema"], stream["key_properties"])
Context.counts[stream["tap_stream_id"]] = 0
Comment on lines 108 to 111
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can use the following function instead

catalog.get_selected_streams(state):


# Loop over streams in catalog
for catalog_entry in Context.catalog['streams']:
stream_id = catalog_entry['tap_stream_id']
for catalog_entry in Context.catalog["streams"]:
stream_id = catalog_entry["tap_stream_id"]
stream = Context.stream_objects[stream_id]()

if not Context.is_selected(stream_id):
LOGGER.info('Skipping stream: %s', stream_id)
LOGGER.info("Skipping stream: %s", stream_id)
continue

LOGGER.info('Syncing stream: %s', stream_id)
LOGGER.info("Syncing stream: %s", stream_id)

if not Context.state.get('bookmarks'):
Context.state['bookmarks'] = {}
Context.state['bookmarks']['currently_sync_stream'] = stream_id
if not Context.state.get("bookmarks"):
Context.state["bookmarks"] = {}
Context.state["bookmarks"]["currently_sync_stream"] = stream_id

with Transformer() as transformer:
for rec in stream.sync():
extraction_time = singer.utils.now()
record_schema = catalog_entry['schema']
record_metadata = metadata.to_map(catalog_entry['metadata'])
record_schema = catalog_entry["schema"]
record_metadata = metadata.to_map(catalog_entry["metadata"])
rec = transformer.transform(rec, record_schema, record_metadata)
singer.write_record(stream_id,
rec,
time_extracted=extraction_time)
singer.write_record(stream_id, rec, time_extracted=extraction_time)
Context.counts[stream_id] += 1

Context.state['bookmarks'].pop('currently_sync_stream')
Context.state["bookmarks"].pop("currently_sync_stream")
singer.write_state(Context.state)

LOGGER.info('----------------------')
LOGGER.info("----------------------")
for stream_id, stream_count in Context.counts.items():
LOGGER.info('%s: %d', stream_id, stream_count)
LOGGER.info('----------------------')
LOGGER.info("%s: %d", stream_id, stream_count)
LOGGER.info("----------------------")


@utils.handle_top_exception(LOGGER)
Expand All @@ -160,10 +150,10 @@ def main():

# Set context.
creds = {
"client_id": args.config['client_id'],
"client_secret": args.config['client_secret'],
"redirect_uri": args.config['redirect_uri'],
"refresh_token": args.config['refresh_token']
"client_id": args.config["client_id"],
"client_secret": args.config["client_secret"],
"redirect_uri": args.config["redirect_uri"],
"refresh_token": args.config["refresh_token"],
}

# As we passed 'request_timeout', we need to add a whole 'args.config' rather than adding 'creds'
Expand All @@ -174,7 +164,7 @@ def main():
# If discover flag was passed, run discovery mode and dump output to stdout
if args.discover:
catalog = discover()
print(json.dumps(catalog, indent=2))
print(json.dumps(catalog, indent=2)) # noqa
# Otherwise run in sync mode
else:
Context.tap_start = utils.now()
Expand Down
Loading