thunkmetrc 0.2.2__tar.gz
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.
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# SECURITY & SECRETS
|
|
3
|
+
# ==============================================================================
|
|
4
|
+
.env
|
|
5
|
+
.env.*
|
|
6
|
+
!.env.example
|
|
7
|
+
.npmrc
|
|
8
|
+
settings.xml
|
|
9
|
+
*.pem
|
|
10
|
+
*.key
|
|
11
|
+
local.properties
|
|
12
|
+
|
|
13
|
+
# ==============================================================================
|
|
14
|
+
# OS & Environment
|
|
15
|
+
# ==============================================================================
|
|
16
|
+
.DS_Store
|
|
17
|
+
.DS_Store?
|
|
18
|
+
.AppleDouble
|
|
19
|
+
.LSOverride
|
|
20
|
+
Icon
|
|
21
|
+
._*
|
|
22
|
+
.Spotlight-V100
|
|
23
|
+
.Trashes
|
|
24
|
+
.Thumbs.db
|
|
25
|
+
desktop.ini
|
|
26
|
+
ehthumbs.db
|
|
27
|
+
Thumbs.db
|
|
28
|
+
|
|
29
|
+
# ==============================================================================
|
|
30
|
+
# IDE & Editors
|
|
31
|
+
# ==============================================================================
|
|
32
|
+
# VS Code
|
|
33
|
+
.vscode/*
|
|
34
|
+
!.vscode/settings.json
|
|
35
|
+
!.vscode/tasks.json
|
|
36
|
+
!.vscode/launch.json
|
|
37
|
+
!.vscode/extensions.json
|
|
38
|
+
*.code-workspace
|
|
39
|
+
.history/
|
|
40
|
+
|
|
41
|
+
# Visual Studio
|
|
42
|
+
*.suo
|
|
43
|
+
*.user
|
|
44
|
+
*.userosscache
|
|
45
|
+
*.sln.docstates
|
|
46
|
+
|
|
47
|
+
# MonoDevelop / Xamarin Studio
|
|
48
|
+
*.userprefs
|
|
49
|
+
|
|
50
|
+
# IntelliJ / Android Studio
|
|
51
|
+
.idea/
|
|
52
|
+
*.iml
|
|
53
|
+
*.iws
|
|
54
|
+
|
|
55
|
+
# ==============================================================================
|
|
56
|
+
# Build Artifacts & Directories
|
|
57
|
+
# ==============================================================================
|
|
58
|
+
.temp/
|
|
59
|
+
dist/
|
|
60
|
+
out/
|
|
61
|
+
build/
|
|
62
|
+
bin/
|
|
63
|
+
obj/
|
|
64
|
+
target/
|
|
65
|
+
.gradle/
|
|
66
|
+
.externalNativeBuild
|
|
67
|
+
.cxx
|
|
68
|
+
/captures
|
|
69
|
+
|
|
70
|
+
# ==============================================================================
|
|
71
|
+
# Languages & Frameworks
|
|
72
|
+
# ==============================================================================
|
|
73
|
+
|
|
74
|
+
# Go
|
|
75
|
+
*.exe
|
|
76
|
+
*.exe~
|
|
77
|
+
*.dll
|
|
78
|
+
*.so
|
|
79
|
+
*.dylib
|
|
80
|
+
*.test
|
|
81
|
+
*.out
|
|
82
|
+
|
|
83
|
+
# Node.js
|
|
84
|
+
node_modules/
|
|
85
|
+
npm-debug.log*
|
|
86
|
+
yarn-debug.log*
|
|
87
|
+
yarn-error.log*
|
|
88
|
+
package-lock.json
|
|
89
|
+
pnpm-lock.yaml
|
|
90
|
+
yarn.lock
|
|
91
|
+
|
|
92
|
+
# Python
|
|
93
|
+
__pycache__/
|
|
94
|
+
.pytest_cache/
|
|
95
|
+
*.pyc
|
|
96
|
+
sdks/python/dist/
|
|
97
|
+
|
|
98
|
+
# C# / .NET
|
|
99
|
+
[Dd]ebug/
|
|
100
|
+
[Dd]ebugPublic/
|
|
101
|
+
[Rr]elease/
|
|
102
|
+
[Rr]eleases/
|
|
103
|
+
x64/
|
|
104
|
+
x86/
|
|
105
|
+
Win32/
|
|
106
|
+
ARM/
|
|
107
|
+
ARM64/
|
|
108
|
+
bld/
|
|
109
|
+
[Ll]og/
|
|
110
|
+
[Ll]ogs/
|
|
111
|
+
|
|
112
|
+
# ==============================================================================
|
|
113
|
+
# Project Specific
|
|
114
|
+
# ==============================================================================
|
|
115
|
+
|
|
116
|
+
# Scraper Outputs
|
|
117
|
+
specs/metrc-responses
|
|
118
|
+
*.html
|
|
119
|
+
|
|
120
|
+
# Logs
|
|
121
|
+
*.log
|
|
122
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: thunkmetrc
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: High-level ThunkMetrc Python SDK
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: python-dateutil>=2.8.2
|
|
8
|
+
Requires-Dist: thunkmetrc-wrapper==0.2.2
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# ThunkMetrc
|
|
12
|
+
|
|
13
|
+
High-level Python SDK for Metrc with convenience functions like `active_packages_inventory_sync`.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install thunkmetrc
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from thunkmetrc import active_packages_inventory_sync
|
|
25
|
+
from thunkmetrc_wrapper import MetrcWrapper
|
|
26
|
+
|
|
27
|
+
wrapper = MetrcWrapper("https://api.metrc.com", "vendor_key", "user_key")
|
|
28
|
+
|
|
29
|
+
# Sync active packages inventory
|
|
30
|
+
packages = active_packages_inventory_sync(
|
|
31
|
+
wrapper,
|
|
32
|
+
"license_number",
|
|
33
|
+
last_known_sync=None,
|
|
34
|
+
buffer_minutes=5
|
|
35
|
+
)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
MIT
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# ThunkMetrc
|
|
2
|
+
|
|
3
|
+
High-level Python SDK for Metrc with convenience functions like `active_packages_inventory_sync`.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install thunkmetrc
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from thunkmetrc import active_packages_inventory_sync
|
|
15
|
+
from thunkmetrc_wrapper import MetrcWrapper
|
|
16
|
+
|
|
17
|
+
wrapper = MetrcWrapper("https://api.metrc.com", "vendor_key", "user_key")
|
|
18
|
+
|
|
19
|
+
# Sync active packages inventory
|
|
20
|
+
packages = active_packages_inventory_sync(
|
|
21
|
+
wrapper,
|
|
22
|
+
"license_number",
|
|
23
|
+
last_known_sync=None,
|
|
24
|
+
buffer_minutes=5
|
|
25
|
+
)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## License
|
|
29
|
+
|
|
30
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "thunkmetrc"
|
|
7
|
+
version = "0.2.2"
|
|
8
|
+
description = "High-level ThunkMetrc Python SDK"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"thunkmetrc-wrapper==0.2.2",
|
|
14
|
+
"python-dateutil>=2.8.2" # Useful for date handling if needed
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[tool.hatch.build.targets.wheel]
|
|
18
|
+
packages = ["src/thunkmetrc"]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from typing import List, Optional, Any, Dict
|
|
2
|
+
from datetime import datetime, timedelta, timezone
|
|
3
|
+
from thunkmetrc.wrapper import MetrcWrapper
|
|
4
|
+
|
|
5
|
+
async def active_packages_inventory_sync(
|
|
6
|
+
wrapper: MetrcWrapper,
|
|
7
|
+
license_number: str,
|
|
8
|
+
last_known_sync: Optional[datetime] = None,
|
|
9
|
+
buffer_minutes: int = 5
|
|
10
|
+
) -> List[Dict[str, Any]]:
|
|
11
|
+
"""
|
|
12
|
+
Syncs all active packages modified within the time window.
|
|
13
|
+
|
|
14
|
+
:param wrapper: MetrcWrapper instance
|
|
15
|
+
:param license_number: Facility license number
|
|
16
|
+
:param last_known_sync: Last successful sync time (datetime). If None, defaults to 24h ago.
|
|
17
|
+
:param buffer_minutes: Buffer to subtract from start time (default 5).
|
|
18
|
+
:return: List of active packages
|
|
19
|
+
"""
|
|
20
|
+
end_time = datetime.now(timezone.utc)
|
|
21
|
+
|
|
22
|
+
if last_known_sync:
|
|
23
|
+
start_time = last_known_sync - timedelta(minutes=buffer_minutes)
|
|
24
|
+
else:
|
|
25
|
+
# Default to 24 hours ago if no sync state
|
|
26
|
+
start_time = end_time - timedelta(hours=24)
|
|
27
|
+
|
|
28
|
+
# Ensure UTC if naive (assume UTC if naive, or convert)
|
|
29
|
+
if start_time.tzinfo is None:
|
|
30
|
+
start_time = start_time.replace(tzinfo=timezone.utc)
|
|
31
|
+
if end_time.tzinfo is None:
|
|
32
|
+
end_time = end_time.replace(tzinfo=timezone.utc)
|
|
33
|
+
|
|
34
|
+
# Format as ISO 8601 strings (e.g. 2023-10-26T12:00:00+00:00)
|
|
35
|
+
# isoformat() produces valid ISO 8601
|
|
36
|
+
start_str = start_time.isoformat()
|
|
37
|
+
end_str = end_time.isoformat()
|
|
38
|
+
|
|
39
|
+
all_packages: List[Dict[str, Any]] = []
|
|
40
|
+
page = 1
|
|
41
|
+
page_size = 20
|
|
42
|
+
|
|
43
|
+
while True:
|
|
44
|
+
# Wrapper method signature (from generator):
|
|
45
|
+
# async def packages_get_active_v2(self, last_modified_end: Optional[str] = None, last_modified_start: Optional[str] = None, license_number: Optional[str] = None, page_number: Optional[str] = None, page_size: Optional[str] = None, body: Any = None) -> Any:
|
|
46
|
+
|
|
47
|
+
# Note: Argument order matters if positional, but keyword args are safer.
|
|
48
|
+
# Generated code uses keyword arguments for query params in the wrapper calling client?
|
|
49
|
+
# Actually wrapper generator adds them as keyword args to the signature defaults.
|
|
50
|
+
|
|
51
|
+
response = await wrapper.packages_get_active_v2(
|
|
52
|
+
last_modified_end=end_str,
|
|
53
|
+
last_modified_start=start_str,
|
|
54
|
+
license_number=license_number,
|
|
55
|
+
page_number=str(page),
|
|
56
|
+
page_size=str(page_size)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
if response:
|
|
60
|
+
# Response should be a dict if parsed from JSON
|
|
61
|
+
# e.g. { "Data": [...], "TotalPages": 1 }
|
|
62
|
+
data = response.get("Data")
|
|
63
|
+
if isinstance(data, list):
|
|
64
|
+
all_packages.extend(data)
|
|
65
|
+
|
|
66
|
+
total_pages = response.get("TotalPages")
|
|
67
|
+
if isinstance(total_pages, int):
|
|
68
|
+
if page >= total_pages:
|
|
69
|
+
break
|
|
70
|
+
else:
|
|
71
|
+
# No pagination info or single page?
|
|
72
|
+
break
|
|
73
|
+
else:
|
|
74
|
+
break
|
|
75
|
+
|
|
76
|
+
page += 1
|
|
77
|
+
|
|
78
|
+
return all_packages
|