-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Mock a simple list of time entries refs #4 * Add TimeEntries client Ref: #4 * Switch from hard-coded to actual Toggl API calls - We use the actual TimeEntries API to fetch data from Toggl - Record and replay network traffic using pytest-recording refs: #4 * Add missing TOGGL_API_TOKEN environment variable * Move output formatting into a result module refs: #4 * Add a 'entries list' command usage example Simple demonstration of the only available command :) refs: #4 * Improve help messages add clean up default options Default values for date-related options were a little messy. I hope this change makes the date logic a little more readable.
- Loading branch information
Showing
10 changed files
with
437 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ venv | |
.pytest_cache | ||
*.egg-info | ||
.DS_Store | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
interactions: | ||
- request: | ||
body: null | ||
headers: | ||
Accept: | ||
- '*/*' | ||
Accept-Encoding: | ||
- gzip, deflate | ||
Connection: | ||
- keep-alive | ||
User-Agent: | ||
- python-requests/2.28.2 | ||
method: GET | ||
uri: https://api.track.toggl.com/api/v9/me/time_entries?start_date=2023-01-26T00%3A00%3A00Z&end_date=2023-01-27T00%3A00%3A00Z | ||
response: | ||
body: | ||
string: !!binary | | ||
H4sIAAAAAAAEA82Z3YrjNhTHX0X4thnQhyXbutvOdGGhpYUpFLosgybRJN44tmvLm86WvkEXel0K | ||
veoL9Mn6CD124iSKUidkbLOQm8gmkc7v/M+X3v7ixTNP0pBEhHIcBRNvnRXLMldT/VA/ISHhmIQT | ||
Ly+y93pqNotB6DMeUFg2qlw2a2mVJBPvMU4S9ZhoTz6ppNQTrzSqMJ70KKbsBpMbKr6nVFIuGf8C | ||
Y4mxV7+T5c4r3JeM/QhPZ1WhTJylsJeAwT/OdDkt4nyz5N1mq1WVxuZZoldJkq1RrooyTucoe0Jv | ||
vvsgkJrNCl2WukRxCp+5Lg3K41wncarh142al55865nnXMuyyvMMtvuuWYdj1Y8IxUGIBYZF2EqW | ||
Js+eNEUFZ1PuwZpd7w+miw+6eJjpRBs9e6jf35ipKmG5MbyghDE28Srr29o2ffOttfmvkz0zHFIq | ||
6BjMiPS5JGR/tFPMGqw2M+pTv4PZ6/jnHTFdFFmBpkmsU0AEHFBcosdEpUuk0hmAfF8Buyd4x8Qr | ||
fW/UKu8f4JFnjgHQH0V0G4C4C+CWsQ2QjEBvIwqQ4kZym6/nxOZ45BisyHiscHieFbZZQST43+jY | ||
l9JewOrA+QZnhRnh4LrDJzMsWST94CwrHNmsWES7cL36WBUa3cfzFNLWN9msSjRSlVlAbIynTT58 | ||
gIw8hcwGOQ0yjFFxUqI3ZVn1ntUaoeFof8KB4YVhAHntMqHREPskYviqQoSEkkeSH7ilm9S2eG12 | ||
PKoLJVtq//716R90F6epLnZZ6SqtOA7Vo7lbcx3UEGFAfIqhAhlcKiSQhEHpt3ckx9w1kVDSo7pP | ||
0Kiz7vtspNJuf3/CHtmREwVgKETILywAW/bXSUVIH8B0SaXFa0sFugfuSuWP39D9ojIGivA5WkKd | ||
jR61WWudokW2gkAH5d56oYyG6vlFYmr3NAiQ1qCHYuJCYH5Z6NrxvA4IlxyaqIOo7Ippw4zaQBgR | ||
IHY7dh02UZ+PmLbbH4TdzvgWPD/iPnjr8JGQQ8Ugib8/mgtvy9eGd0JMd0WWo4VWM12gJJujuq+t | ||
W93bJKtmr6FfNQhklJpyJ6R+ml3iOODQsc4XBBPI9GPgwUz6Xc0unL4haOOhgjja+ipRJZRs36ZN | ||
RSfRTxVMIGCcUaKnIluhO53GH9FtVi6rtH9CR142NCEakCAYRUBMYtI9QiIwP4JSStiEOPPdhrZW | ||
CtTYMEXKijoh3aAftF7CnKcZA+3HQyutDTy3x0NRxAQkufPToXZDe9EPjQPmZTwQFwmmzWXX5SIK | ||
KCTr6oGg8INp3zEN4kfRcS6COvpP9HWVThc7819TRsMfAn5+EGJ7tHZrrcPkQWjI61HX8NGJSgyp | ||
sbMU2wAhtu+DOzi+Xz6n052d28RQr50agZILnHz7z+M5OQ64CEbJChBw4HPG7g0a2+6U1FnLrrjm | ||
Clp5GGRmayfqvzDKON7Ro9+frJowjKBHuTcgoGcoOrrGYmTD6Mjx6xH7MQBV17lUwji5uTWonFHy | ||
PFPJSRWwC1Sw3cZoKgiCkNH6lmbw6IOhC/Ql6ew7tpxsFUTYjfW9Rx/HQwZ2/iDAkGMhh11g94hj | ||
Gom6Wb/izgwHcEcn/YN05nQMQAY+5HgkzARUAHbwMdl8ntyYQk2XEvoFuFSpL1QQNAlFrPd9wjVp | ||
t93EIJ7fWvAg7QYwAMER2HRwAE03yrv8HhjBvAEfDa+ICJ0LsCEBbDcxHgAGN8eX5d+2bLpOAaIu | ||
ezrTb51765GuHXgo908UmX//jr4stFo+QXe2K4Cu8njHMXqMOa3FLI8nGBrhETy+vu/t7rHA4A0T | ||
2+CMRs7Ib0iPdxyjRwC7kPPuP1wjPywqIQAA | ||
headers: | ||
Alt-Svc: | ||
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 | ||
Cache-Control: | ||
- no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0 | ||
Content-Encoding: | ||
- gzip | ||
Content-Type: | ||
- application/json; charset=utf-8 | ||
Date: | ||
- Fri, 27 Jan 2023 07:32:41 GMT | ||
Instance: | ||
- time-public-api2 | ||
Referrer-Policy: | ||
- strict-origin-when-cross-origin | ||
Server: | ||
- nginx | ||
Strict-Transport-Security: | ||
- max-age=15552000; includeSubDomains | ||
Transfer-Encoding: | ||
- chunked | ||
Vary: | ||
- Accept-Encoding | ||
Via: | ||
- 1.1 google | ||
X-Content-Type-Options: | ||
- nosniff | ||
X-Request-ID: | ||
- 30ab28ce94254c279dcb9a3437e2470e | ||
X-Service-Level: | ||
- GREEN | ||
X-Toggl-Request-Id: | ||
- 30ab28ce94254c279dcb9a3437e2470e | ||
X-We-are-hiring: | ||
- https://toggl.com/jobs/ | ||
status: | ||
code: 200 | ||
message: OK | ||
version: 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from typing import Any | ||
|
||
import pytest | ||
from click.testing import Result | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
def vcr_config(): | ||
return { | ||
"filter_headers": ["authorization"], | ||
} | ||
|
||
|
||
@pytest.fixture() | ||
def save_to_tmp(): | ||
"""Saves the result object to the filesystem for inspection.""" | ||
def wrapper(output: Any): | ||
with open("/tmp/output.txt", "w") as f: | ||
f.write(str(output)) | ||
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import click.testing | ||
import pytest | ||
from click.testing import CliRunner | ||
|
||
from toggl_track.cli import cli | ||
|
||
|
||
env = { | ||
"TOGGL_API_TOKEN": "1234567890abcdef1234567890abcdef", # fake token for testing | ||
} | ||
|
||
|
||
@pytest.mark.vcr | ||
@pytest.mark.block_network | ||
def test_entries(): | ||
runner = CliRunner() | ||
with runner.isolated_filesystem(): | ||
result = runner.invoke( | ||
cli, | ||
["entries", "list", "--start-date", "2023-01-26", "--end-date", "2023-01-27"], | ||
env=env, | ||
) | ||
assert result.exit_code == 0 | ||
assert ( | ||
result.output | ||
== """ Time Entries | ||
At Description Start Stop Duration Tags | ||
────────────────────────────────────────────────────────────────────────────── | ||
2023-01-26 Community: 10:25 PM 10:54 PM 28 minutes type:support | ||
Allow parsing | ||
of IPv6 | ||
addresses in | ||
ingest | ||
pipeline | ||
2023-01-26 Community: 09:45 PM 10:25 PM 40 minutes type:support | ||
Fix parsing | ||
error client | ||
port is blank | ||
and adjust | ||
for timeStamp | ||
2023-01-26 Community: 09:45 PM 09:45 PM a second | ||
Fix parsing | ||
error client | ||
port is blank | ||
and adjust | ||
for timeStamp | ||
2023-01-26 Community: 09:45 PM 09:45 PM 2 seconds | ||
Fix parsing | ||
error client | ||
port is blank | ||
and adjust | ||
for timeStamp | ||
2023-01-26 Community: 08:39 PM 09:45 PM an hour type:support | ||
Azure Signin | ||
Module | ||
authenticati… | ||
Issue | ||
2023-01-26 🍲 Dinner 06:59 PM 08:39 PM an hour | ||
2023-01-26 Community: 05:13 PM 06:58 PM an hour type:support | ||
Azure Signin | ||
Module | ||
authenticati… | ||
Issue | ||
2023-01-26 🚌 Shuttling 04:48 PM 05:13 PM 25 minutes | ||
kids between | ||
home and | ||
whatever | ||
2023-01-26 Community: 03:55 PM 04:48 PM 52 minutes type:support | ||
Azure Signin | ||
Module | ||
authenticati… | ||
Issue | ||
2023-01-26 Drop header 03:47 PM 03:55 PM 8 minutes type:support | ||
log line in | ||
CloudFront | ||
events | ||
2023-01-26 ElasticOnAzu… 03:03 PM 03:47 PM 43 minutes type:support | ||
questions | ||
from Deniz | ||
Coskun | ||
2023-01-26 Cloud 01:01 PM 02:30 PM an hour type:meeting | ||
Monitoring - | ||
Weekly | ||
2023-01-26 🍜 Lunch 12:35 PM 01:00 PM 24 minutes | ||
2023-01-26 sync 12:06 PM 12:35 PM 28 minutes type:sync | ||
2023-01-26 gather town 11:31 AM 12:06 PM 35 minutes type:meeting | ||
2023-01-26 azure2: 10:55 AM 11:31 AM 35 minutes type:goal | ||
follow up | ||
2023-01-26 sync 08:24 AM 10:55 AM 2 hours type:sync | ||
2023-01-26 toggl-track: 07:28 AM 08:08 AM 39 minutes | ||
list time | ||
entries | ||
2023-01-26 toggl-track: 06:48 AM 07:17 AM 28 minutes | ||
list time | ||
entries | ||
2023-01-26 🥐 Breakfast 06:06 AM 06:48 AM 42 minutes | ||
2023-01-26 toggl-track: 05:11 AM 06:06 AM 54 minutes | ||
list time | ||
entries | ||
""" | ||
) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
from datetime import datetime | ||
|
||
from toggl_track.result import TimeEntriesListResult | ||
from toggl_track.toggl import TimeEntry | ||
|
||
|
||
def test_empty_timeentrieslistresult_as_str(): | ||
entries = [] | ||
result = TimeEntriesListResult(entries) | ||
|
||
assert str(result) == "No time entries found." | ||
|
||
|
||
def test_empty_timeentrieslistresult_as_str(): | ||
entries = [TimeEntry( | ||
id=1, | ||
workspace_id=1, | ||
user_id=1, | ||
project_id=1, | ||
task_id=None, | ||
billable=False, | ||
at=datetime(2021, 1, 25, 0, 0), | ||
description="community:", | ||
start=datetime(2021, 1, 25, 23, 4), | ||
stop=datetime(2021, 1, 25, 23, 27), | ||
duration=1379, | ||
tags=["type:support"] | ||
)] | ||
result = TimeEntriesListResult(entries) | ||
|
||
assert str(result) == """ Time Entries | ||
At Description Start Stop Duration Tags | ||
──────────────────────────────────────────────────────────────────────────── | ||
2021-01-25 community: 11:04 PM 11:27 PM 22 minutes type:support | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,54 @@ | ||
import datetime | ||
from datetime import timedelta | ||
|
||
import click | ||
|
||
from .toggl import TimeEntries | ||
from .result import TimeEntriesListResult | ||
|
||
|
||
# default reference date for all date options | ||
now = datetime.datetime.now() | ||
|
||
def as_str(reference_date: datetime = now) -> str: | ||
"""Formats a `reference_date` into a string. | ||
Helper function to be used as a default value for click options. | ||
:param reference_date: a datetime object""" | ||
return reference_date.strftime("%Y-%m-%dT%H:%M:%S") | ||
|
||
|
||
@click.group() | ||
@click.version_option() | ||
def cli(): | ||
"CLI tool and Python library to access Toggl Track https://toggl.com/track/" | ||
|
||
|
||
@cli.command(name="command") | ||
@click.argument( | ||
"example" | ||
@cli.group() | ||
def entries(): | ||
"Time entries commands" | ||
pass | ||
|
||
|
||
|
||
@entries.command(name="list") | ||
@click.option( | ||
"--start-date", | ||
type=click.DateTime(), | ||
default=as_str(now - timedelta(hours=24)), | ||
help="Start date (default: 24 hours ago)" | ||
) | ||
@click.option( | ||
"-o", | ||
"--option", | ||
help="An example option", | ||
"--end-date", | ||
type=click.DateTime(), | ||
default=as_str(now) | ||
) | ||
def first_command(example, option): | ||
"Command description goes here" | ||
click.echo("Here is some output") | ||
def list_entries(start_date: datetime, end_date: datetime): | ||
"""Returns a list of the latest time entries (default: last 24 hours)""" | ||
|
||
client = TimeEntries.from_environment() | ||
|
||
click.echo(TimeEntriesListResult( | ||
client.list(start_date, end_date)) | ||
) |
Oops, something went wrong.