pytekukko 0.16.0__py3-none-any.whl → 0.17.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytekukko/__init__.py +3 -3
- pytekukko/examples/print_collection_schedules.py +12 -3
- pytekukko/examples/print_invoice_headers.py +10 -3
- pytekukko/examples/print_next_collections.py +10 -3
- pytekukko/models.py +7 -7
- {pytekukko-0.16.0.dist-info → pytekukko-0.17.0.dist-info}/METADATA +33 -10
- pytekukko-0.17.0.dist-info/RECORD +14 -0
- {pytekukko-0.16.0.dist-info → pytekukko-0.17.0.dist-info}/WHEEL +1 -1
- {pytekukko-0.16.0.dist-info → pytekukko-0.17.0.dist-info}/entry_points.txt +0 -1
- pytekukko/examples/update_google_calendar.py +0 -211
- pytekukko-0.16.0.dist-info/RECORD +0 -15
- {pytekukko-0.16.0.dist-info → pytekukko-0.17.0.dist-info/licenses}/LICENSE +0 -0
- {pytekukko-0.16.0.dist-info → pytekukko-0.17.0.dist-info}/top_level.txt +0 -0
pytekukko/__init__.py
CHANGED
@@ -13,7 +13,7 @@ from aiohttp import ClientResponse, ClientResponseError, ClientSession
|
|
13
13
|
from .exceptions import UnexpectedResponseStructureError
|
14
14
|
from .models import CustomerData, InvoiceHeader, Service
|
15
15
|
|
16
|
-
__version__ = "0.
|
16
|
+
__version__ = "0.17.0"
|
17
17
|
DEFAULT_BASE_URL = "https://tilasto.jatekukko.fi/jatekukko/"
|
18
18
|
|
19
19
|
SERVICE_TIMEZONE = ZoneInfo("Europe/Helsinki")
|
@@ -77,7 +77,7 @@ class Pytekukko:
|
|
77
77
|
params=params,
|
78
78
|
)
|
79
79
|
|
80
|
-
return cast(list[date], _unmarshal(response_data))
|
80
|
+
return cast("list[date]", _unmarshal(response_data))
|
81
81
|
|
82
82
|
async def get_invoice_headers(self) -> list[InvoiceHeader]:
|
83
83
|
"""Get headers of available invoices."""
|
@@ -114,7 +114,7 @@ class Pytekukko:
|
|
114
114
|
raise_for_status=True,
|
115
115
|
) as response:
|
116
116
|
# NOTE(scop): could check that we got {"response":"OK"}
|
117
|
-
return cast(dict[str, str], await response.json())
|
117
|
+
return cast("dict[str, str]", await response.json())
|
118
118
|
|
119
119
|
async def logout(self) -> None:
|
120
120
|
"""Log out the current session."""
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
"""Print collection schedules."""
|
4
4
|
|
5
|
+
import argparse
|
5
6
|
import asyncio
|
6
7
|
import json
|
7
8
|
import sys
|
@@ -13,13 +14,21 @@ import pytekukko
|
|
13
14
|
from pytekukko.examples import example_argparser, example_client
|
14
15
|
|
15
16
|
|
16
|
-
|
17
|
-
"""
|
17
|
+
def argparser() -> argparse.ArgumentParser:
|
18
|
+
"""Return an argument parser for the example.
|
19
|
+
|
20
|
+
This is a separate function to facilitate shtab generated completions.
|
21
|
+
"""
|
18
22
|
argparser = example_argparser(__doc__)
|
19
23
|
argparser.add_argument(
|
20
24
|
"-i", "--icalendar", action="store_true", help="output iCalendar"
|
21
25
|
)
|
22
|
-
|
26
|
+
return argparser
|
27
|
+
|
28
|
+
|
29
|
+
async def run_example() -> None:
|
30
|
+
"""Run the example."""
|
31
|
+
args = argparser().parse_args()
|
23
32
|
|
24
33
|
client, cookie_jar, cookie_jar_path = example_client(args)
|
25
34
|
|
@@ -2,17 +2,24 @@
|
|
2
2
|
|
3
3
|
"""Print basic info on invoices."""
|
4
4
|
|
5
|
+
import argparse
|
5
6
|
import asyncio
|
6
7
|
import json
|
7
8
|
|
8
9
|
from pytekukko.examples import example_argparser, example_client
|
9
10
|
|
10
11
|
|
12
|
+
def argparser() -> argparse.ArgumentParser:
|
13
|
+
"""Return an argument parser for the example.
|
14
|
+
|
15
|
+
This is a separate function to facilitate shtab generated completions.
|
16
|
+
"""
|
17
|
+
return example_argparser(__doc__)
|
18
|
+
|
19
|
+
|
11
20
|
async def run_example() -> None:
|
12
21
|
"""Run the example."""
|
13
|
-
client, cookie_jar, cookie_jar_path = example_client(
|
14
|
-
example_argparser(__doc__).parse_args(),
|
15
|
-
)
|
22
|
+
client, cookie_jar, cookie_jar_path = example_client(argparser().parse_args())
|
16
23
|
|
17
24
|
async with client.session:
|
18
25
|
data = [
|
@@ -2,17 +2,24 @@
|
|
2
2
|
|
3
3
|
"""Print next collection dates."""
|
4
4
|
|
5
|
+
import argparse
|
5
6
|
import asyncio
|
6
7
|
import json
|
7
8
|
|
8
9
|
from pytekukko.examples import example_argparser, example_client
|
9
10
|
|
10
11
|
|
12
|
+
def argparser() -> argparse.ArgumentParser:
|
13
|
+
"""Return an argument parser for the example.
|
14
|
+
|
15
|
+
This is a separate function to facilitate shtab generated completions.
|
16
|
+
"""
|
17
|
+
return example_argparser(__doc__)
|
18
|
+
|
19
|
+
|
11
20
|
async def run_example() -> None:
|
12
21
|
"""Run the example."""
|
13
|
-
client, cookie_jar, cookie_jar_path = example_client(
|
14
|
-
example_argparser(__doc__).parse_args(),
|
15
|
-
)
|
22
|
+
client, cookie_jar, cookie_jar_path = example_client(argparser().parse_args())
|
16
23
|
|
17
24
|
async with client.session:
|
18
25
|
data = [
|
pytekukko/models.py
CHANGED
@@ -21,12 +21,12 @@ class Service:
|
|
21
21
|
@property
|
22
22
|
def name(self) -> str:
|
23
23
|
"""Get service name."""
|
24
|
-
return cast(str, self.raw_data["ASTNimi"])
|
24
|
+
return cast("str", self.raw_data["ASTNimi"])
|
25
25
|
|
26
26
|
@property
|
27
27
|
def pos(self) -> int:
|
28
28
|
"""Get "pos" value."""
|
29
|
-
return cast(int, self.raw_data["ASTPos"])
|
29
|
+
return cast("int", self.raw_data["ASTPos"])
|
30
30
|
|
31
31
|
@property
|
32
32
|
def next_collection(self) -> date | None:
|
@@ -50,12 +50,12 @@ class CustomerData:
|
|
50
50
|
@property
|
51
51
|
def customer_number(self) -> str:
|
52
52
|
"""Get customer number."""
|
53
|
-
return cast(str, self.raw_data["asiakasnro"])
|
53
|
+
return cast("str", self.raw_data["asiakasnro"])
|
54
54
|
|
55
55
|
@property
|
56
56
|
def name(self) -> str:
|
57
57
|
"""Get customer name."""
|
58
|
-
return cast(str, self.raw_data["nimi"])
|
58
|
+
return cast("str", self.raw_data["nimi"])
|
59
59
|
|
60
60
|
|
61
61
|
@dataclass
|
@@ -71,14 +71,14 @@ class InvoiceHeader:
|
|
71
71
|
@property
|
72
72
|
def name(self) -> str:
|
73
73
|
"""Get customer number."""
|
74
|
-
return cast(str, self.raw_data["name"])
|
74
|
+
return cast("str", self.raw_data["name"])
|
75
75
|
|
76
76
|
@property
|
77
77
|
def due_date(self) -> date:
|
78
78
|
"""Get due date."""
|
79
|
-
return cast(date, self.raw_data["dueDate"])
|
79
|
+
return cast("date", self.raw_data["dueDate"])
|
80
80
|
|
81
81
|
@property
|
82
82
|
def total(self) -> float:
|
83
83
|
"""Get total amount."""
|
84
|
-
return cast(float, self.raw_data["total"])
|
84
|
+
return cast("float", self.raw_data["total"])
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: pytekukko
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.17.0
|
4
4
|
Summary: Jätekukko Omakukko API client
|
5
5
|
Author-email: Ville Skyttä <ville.skytta@iki.fi>
|
6
6
|
License:
|
@@ -219,19 +219,20 @@ Classifier: Typing :: Typed
|
|
219
219
|
Requires-Python: >=3.10
|
220
220
|
Description-Content-Type: text/markdown
|
221
221
|
License-File: LICENSE
|
222
|
-
Requires-Dist: aiohttp
|
222
|
+
Requires-Dist: aiohttp~=3.4
|
223
223
|
Provides-Extra: examples
|
224
|
-
Requires-Dist: python-dotenv
|
225
|
-
Requires-Dist:
|
226
|
-
|
224
|
+
Requires-Dist: python-dotenv<2,>=0.10; extra == "examples"
|
225
|
+
Requires-Dist: icalendar<7,>=5; extra == "examples"
|
226
|
+
Dynamic: license-file
|
227
227
|
|
228
228
|
# pytekukko -- Jätekukko Omakukko API client
|
229
229
|
|
230
230
|
[](https://pypi.org/project/pytekukko/)
|
231
231
|
[](https://badge.fury.io/py/pytekukko)
|
232
|
-
[](https://github.com/scop/pytekukko/actions/workflows/test.yaml)
|
233
|
+
[](https://scorecard.dev/viewer/?uri=github.com%2Fscop%2Fpytekukko)
|
233
234
|
|
234
|
-
Simple asyncio client for the [Jätekukko](https://www.jatekukko.fi)
|
235
|
+
Simple Python asyncio client for the [Jätekukko](https://www.jatekukko.fi)
|
235
236
|
[Omakukko](https://tilasto.jatekukko.fi/indexservice2.jsp) API.
|
236
237
|
|
237
238
|
The API of this package is modeled closely after the Omakukko
|
@@ -254,6 +255,8 @@ detected. If the detection is successful, there is no need to
|
|
254
255
|
separately track session expiration or use the `login` method in the
|
255
256
|
first place.
|
256
257
|
|
258
|
+
## Command line examples
|
259
|
+
|
257
260
|
For usage examples, see utilities in the `pytekukko.examples`
|
258
261
|
package. Executables and dependencies for these are installed when the
|
259
262
|
package is installed with the `examples` extra, invoke them with
|
@@ -262,8 +265,28 @@ package is installed with the `examples` extra, invoke them with
|
|
262
265
|
- `pytekukko-collection-schedules`: output collection schedules in JSON
|
263
266
|
- `pytekukko-invoice-headers`: output basic info on invoices in JSON
|
264
267
|
- `pytekukko-next-collections`: output next collection dates in JSON
|
265
|
-
|
266
|
-
|
268
|
+
|
269
|
+
Shell completions for the examples can be generated with
|
270
|
+
[shtab's CLI usage mode](https://docs.iterative.ai/shtab/use/#cli-usage).
|
271
|
+
|
272
|
+
<details>
|
273
|
+
|
274
|
+
```shell
|
275
|
+
shtab \
|
276
|
+
--prog pytekukko-collection-schedules \
|
277
|
+
--prefix pytekukko_collection_schedules \
|
278
|
+
pytekukko.examples.print_collection_schedules.argparser
|
279
|
+
shtab \
|
280
|
+
--prog pytekukko-invoice-headers \
|
281
|
+
--prefix pytekukko_invoice_headers \
|
282
|
+
pytekukko.examples.print_invoice_headers.argparser
|
283
|
+
shtab \
|
284
|
+
--prog pytekukko-next-collections \
|
285
|
+
--prefix pytekukko_next_collections \
|
286
|
+
pytekukko.examples.print_next_collections.argparser
|
287
|
+
```
|
288
|
+
|
289
|
+
</details>
|
267
290
|
|
268
291
|
## Disclaimer
|
269
292
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
pytekukko/__init__.py,sha256=Kp4WRJ0Vfqdicd8E-e0jdu-ndyKA7SgQkUuQan7d6N8,6561
|
2
|
+
pytekukko/exceptions.py,sha256=qGxEaKkr6t0ApvOb-_12PjEUwmEZDCMQ4s5BAgde8Og,353
|
3
|
+
pytekukko/models.py,sha256=W--ERpT3ueoC_cyULHcyB_H41fy5IHhard9JF1rEl_g,2329
|
4
|
+
pytekukko/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
pytekukko/examples/__init__.py,sha256=okWI6GachxrBvvHR-WElMnzki7Fyq-SB5I35gYUziow,2746
|
6
|
+
pytekukko/examples/print_collection_schedules.py,sha256=oGT2Pcju31UDicPnkBm1am56MXUZ-Zh6EzM53B5te-w,2665
|
7
|
+
pytekukko/examples/print_invoice_headers.py,sha256=2dbPJBg0leeFE8_b5EK4KcCPOAjBKKguK_8caBnH_OI,1151
|
8
|
+
pytekukko/examples/print_next_collections.py,sha256=U_2SWnuEqBWrcO8mymrVM71Av67Oqu96P8vCSsKng_A,1128
|
9
|
+
pytekukko-0.17.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
10
|
+
pytekukko-0.17.0.dist-info/METADATA,sha256=Qvp3gNp896-1o1BVE5Bm813WpNhOI2m7bSjcomg_MmM,16688
|
11
|
+
pytekukko-0.17.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
12
|
+
pytekukko-0.17.0.dist-info/entry_points.txt,sha256=_nWk7vXD6paxSMR4HJZArDj0GEdazivnwI1YUJup2GE,285
|
13
|
+
pytekukko-0.17.0.dist-info/top_level.txt,sha256=CozVPCHdY-e4oxKq01MVWfy3ge_5BlV0I465LUsfchk,10
|
14
|
+
pytekukko-0.17.0.dist-info/RECORD,,
|
@@ -2,4 +2,3 @@
|
|
2
2
|
pytekukko-collection-schedules = pytekukko.examples.print_collection_schedules:main [examples]
|
3
3
|
pytekukko-invoice-headers = pytekukko.examples.print_invoice_headers:main [examples]
|
4
4
|
pytekukko-next-collections = pytekukko.examples.print_next_collections:main [examples]
|
5
|
-
pytekukko-update-google-calendar = pytekukko.examples.update_google_calendar:main [examples]
|
@@ -1,211 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
|
3
|
-
"""Update Google Calendar with events for next collections.
|
4
|
-
|
5
|
-
To get the required service account file, enable the Google Calendar API
|
6
|
-
in the Google Cloud console, create service account credentials with
|
7
|
-
access to it, and create keys of type JSON.
|
8
|
-
|
9
|
-
Calendar id is typically the target Google Calendar account e-mail
|
10
|
-
address.
|
11
|
-
"""
|
12
|
-
|
13
|
-
import asyncio
|
14
|
-
import datetime
|
15
|
-
import logging
|
16
|
-
import sys
|
17
|
-
import zoneinfo
|
18
|
-
from collections.abc import Mapping
|
19
|
-
from typing import Any, NamedTuple, cast
|
20
|
-
|
21
|
-
from google.oauth2 import service_account # type: ignore[import-untyped]
|
22
|
-
from googleapiclient.discovery import build # type: ignore[import-untyped]
|
23
|
-
|
24
|
-
from pytekukko.examples import arg_environ_default, example_argparser, example_client
|
25
|
-
|
26
|
-
logging.basicConfig(level=logging.INFO)
|
27
|
-
LOGGER = logging.getLogger(__name__)
|
28
|
-
|
29
|
-
|
30
|
-
class CalendarData(NamedTuple):
|
31
|
-
"""Helper container for calendar data to update."""
|
32
|
-
|
33
|
-
name: str
|
34
|
-
date: datetime.date
|
35
|
-
location: str
|
36
|
-
|
37
|
-
|
38
|
-
# https://developers.google.com/resources/api-libraries/documentation/calendar/v3/python/latest/calendar_v3.events.html
|
39
|
-
def update_google_calendar(
|
40
|
-
credentials: service_account.Credentials,
|
41
|
-
calendar_id: str,
|
42
|
-
data: Mapping[str, CalendarData],
|
43
|
-
) -> None:
|
44
|
-
"""Update the calendar."""
|
45
|
-
service = build(
|
46
|
-
"calendar",
|
47
|
-
"v3",
|
48
|
-
credentials=credentials,
|
49
|
-
# https://github.com/googleapis/google-api-python-client/issues/299
|
50
|
-
# https://github.com/googleapis/google-api-python-client/issues/325
|
51
|
-
cache_discovery=False,
|
52
|
-
)
|
53
|
-
|
54
|
-
# Events with only date set are apparently treated as occurring at midnight,
|
55
|
-
# start of day in calendar's timezone.
|
56
|
-
calendar = service.calendars().get(calendarId=calendar_id).execute()
|
57
|
-
if calendar.get("timeZone"):
|
58
|
-
timezone: datetime.tzinfo = zoneinfo.ZoneInfo(calendar["timeZone"])
|
59
|
-
else:
|
60
|
-
timezone = datetime.timezone.utc
|
61
|
-
since = datetime.datetime.now(timezone).replace(hour=0) - datetime.timedelta(
|
62
|
-
hours=1,
|
63
|
-
)
|
64
|
-
|
65
|
-
events = (
|
66
|
-
service.events()
|
67
|
-
.list(
|
68
|
-
calendarId=calendar_id,
|
69
|
-
orderBy="startTime",
|
70
|
-
singleEvents=True,
|
71
|
-
timeMin=since.isoformat(),
|
72
|
-
privateExtendedProperty="pytekukko-managed=true",
|
73
|
-
)
|
74
|
-
.execute()
|
75
|
-
)
|
76
|
-
|
77
|
-
pos_events: dict[str, dict[str, Any]] = {}
|
78
|
-
for event in events["items"]:
|
79
|
-
# Store first event for each pos for update, delete rest
|
80
|
-
pos = event["extendedProperties"]["private"].get("pytekukko-pos")
|
81
|
-
if pos and pos in data and not pos_events.get(pos):
|
82
|
-
pos_events[pos] = event
|
83
|
-
else:
|
84
|
-
service.events().delete(
|
85
|
-
calendarId=calendar_id,
|
86
|
-
eventId=event["id"],
|
87
|
-
).execute()
|
88
|
-
|
89
|
-
for pos, pos_event_data in data.items():
|
90
|
-
date = pos_event_data.date.isoformat()
|
91
|
-
name = pos_event_data.name or ""
|
92
|
-
description = f"{name} [pos={pos}]".strip()
|
93
|
-
event_data = {
|
94
|
-
"summary": "Jätekukko collection",
|
95
|
-
"description": description,
|
96
|
-
"location": pos_event_data.location or None,
|
97
|
-
"start": {"date": date},
|
98
|
-
"end": {"date": date},
|
99
|
-
# Reminders are "for the authenticated user" per docs.
|
100
|
-
# So for the service account, not the calendar owner :(
|
101
|
-
# No way to set this for the "actual" calendar user from here,
|
102
|
-
# at least while using a service account.
|
103
|
-
"reminders": {"useDefault": False},
|
104
|
-
"transparency": "transparent",
|
105
|
-
"extendedProperties": {
|
106
|
-
"private": {"pytekukko-managed": "true", "pytekukko-pos": pos},
|
107
|
-
},
|
108
|
-
"source": {
|
109
|
-
"url": "https://tilasto.jatekukko.fi/indexservice2.jsp",
|
110
|
-
"title": "Omakukko",
|
111
|
-
},
|
112
|
-
"creator": {
|
113
|
-
"displayName": "Pytekukko",
|
114
|
-
},
|
115
|
-
}
|
116
|
-
|
117
|
-
event = pos_events.get(pos)
|
118
|
-
|
119
|
-
method = None
|
120
|
-
log_level = logging.INFO
|
121
|
-
if event:
|
122
|
-
for key, value in event_data.items():
|
123
|
-
if event.get(key) != value:
|
124
|
-
action = "updated"
|
125
|
-
method = service.events().patch(
|
126
|
-
calendarId=calendar_id,
|
127
|
-
eventId=event["id"],
|
128
|
-
body=event_data,
|
129
|
-
)
|
130
|
-
break
|
131
|
-
else:
|
132
|
-
action = "unchanged"
|
133
|
-
log_level = logging.DEBUG
|
134
|
-
else:
|
135
|
-
action = "created"
|
136
|
-
method = service.events().insert(
|
137
|
-
calendarId=calendar_id,
|
138
|
-
body=event_data,
|
139
|
-
)
|
140
|
-
if method:
|
141
|
-
event = method.execute()
|
142
|
-
LOGGER.log(log_level, "Event %s: %s", action, event.get("htmlLink"))
|
143
|
-
|
144
|
-
|
145
|
-
async def run_example() -> None:
|
146
|
-
"""Run the example."""
|
147
|
-
argparser = example_argparser(__doc__)
|
148
|
-
argparser.add_argument(
|
149
|
-
"--google-calendar-id",
|
150
|
-
type=str,
|
151
|
-
**arg_environ_default("PYTEKUKKO_GOOGLE_CALENDAR_ID"), # type: ignore[arg-type]
|
152
|
-
)
|
153
|
-
argparser.add_argument(
|
154
|
-
"--google-service-account-file",
|
155
|
-
type=str,
|
156
|
-
**arg_environ_default( # type: ignore[arg-type]
|
157
|
-
"PYTEKUKKO_GOOGLE_SERVICE_ACCOUNT_FILE",
|
158
|
-
fallback="service_account.json",
|
159
|
-
),
|
160
|
-
)
|
161
|
-
args = argparser.parse_args()
|
162
|
-
|
163
|
-
if not args.google_calendar_id:
|
164
|
-
print("Google calendar id required", file=sys.stderr) # noqa: T201
|
165
|
-
sys.exit(2)
|
166
|
-
|
167
|
-
client, cookie_jar, cookie_jar_path = example_client(args)
|
168
|
-
|
169
|
-
credentials = service_account.Credentials.from_service_account_file(
|
170
|
-
args.google_service_account_file,
|
171
|
-
)
|
172
|
-
|
173
|
-
async with client.session:
|
174
|
-
services = await client.get_services()
|
175
|
-
if not cookie_jar_path:
|
176
|
-
await client.logout()
|
177
|
-
|
178
|
-
if cookie_jar_path:
|
179
|
-
cookie_jar.save(cookie_jar_path)
|
180
|
-
|
181
|
-
data = {}
|
182
|
-
for service in (x for x in services if x.next_collection):
|
183
|
-
data[str(service.pos)] = CalendarData(
|
184
|
-
name=service.name,
|
185
|
-
date=cast(datetime.date, service.next_collection),
|
186
|
-
location=", ".join(
|
187
|
-
x
|
188
|
-
for x in (
|
189
|
-
service.raw_data.get("owner", {}).get("katu"),
|
190
|
-
service.raw_data.get("owner", {}).get("posti"),
|
191
|
-
)
|
192
|
-
if x
|
193
|
-
),
|
194
|
-
)
|
195
|
-
|
196
|
-
await asyncio.get_event_loop().run_in_executor(
|
197
|
-
None,
|
198
|
-
update_google_calendar,
|
199
|
-
credentials,
|
200
|
-
args.google_calendar_id,
|
201
|
-
data,
|
202
|
-
)
|
203
|
-
|
204
|
-
|
205
|
-
def main() -> None:
|
206
|
-
"""Run example in event loop."""
|
207
|
-
asyncio.run(run_example())
|
208
|
-
|
209
|
-
|
210
|
-
if __name__ == "__main__":
|
211
|
-
main()
|
@@ -1,15 +0,0 @@
|
|
1
|
-
pytekukko/__init__.py,sha256=lh5p0fm7hE6bK-q_ikFuV-4nLOJIhzD7POfOGmYJQGs,6557
|
2
|
-
pytekukko/exceptions.py,sha256=qGxEaKkr6t0ApvOb-_12PjEUwmEZDCMQ4s5BAgde8Og,353
|
3
|
-
pytekukko/models.py,sha256=DePgMRUKXkmJVDiXSREVB7JB3Fe7K-tp9Z9VIv0hcIE,2315
|
4
|
-
pytekukko/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
pytekukko/examples/__init__.py,sha256=okWI6GachxrBvvHR-WElMnzki7Fyq-SB5I35gYUziow,2746
|
6
|
-
pytekukko/examples/print_collection_schedules.py,sha256=Qe5X-3iTGpclh_kHdSIaJEpjXVTXw9BTWPEYajj1Ljc,2446
|
7
|
-
pytekukko/examples/print_invoice_headers.py,sha256=-yjNMdFyGI6X5eAUFtoy4qO9A4HzaJ7Uz7YO_C_7m6o,947
|
8
|
-
pytekukko/examples/print_next_collections.py,sha256=TyxsmQ60zCMOmalIo17YAV9_7yjWSbCYgdZG-ZfOKpU,924
|
9
|
-
pytekukko/examples/update_google_calendar.py,sha256=cbFEtRQtsE2EitvkOD5rQZeJAlspqkPD-2AJyS07kog,6706
|
10
|
-
pytekukko-0.16.0.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
11
|
-
pytekukko-0.16.0.dist-info/METADATA,sha256=ogtbPoHI5YiSq8SSLYurqdM9Ltofr_dPh-HVQRGUONc,16046
|
12
|
-
pytekukko-0.16.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
13
|
-
pytekukko-0.16.0.dist-info/entry_points.txt,sha256=p4qVa_J7SI2g3UoYq9Em_vPBz9DXXzIqL3wpcud2J0o,378
|
14
|
-
pytekukko-0.16.0.dist-info/top_level.txt,sha256=CozVPCHdY-e4oxKq01MVWfy3ge_5BlV0I465LUsfchk,10
|
15
|
-
pytekukko-0.16.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|