pinky-tools 0.1.0.dev1__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.
- pinky_tools-0.1.0.dev1/.github/workflows/ci.yml +36 -0
- pinky_tools-0.1.0.dev1/.github/workflows/publish.yml +32 -0
- pinky_tools-0.1.0.dev1/.github/workflows/release.yml +37 -0
- pinky_tools-0.1.0.dev1/.gitignore +19 -0
- pinky_tools-0.1.0.dev1/.pre-commit-config.yaml +116 -0
- pinky_tools-0.1.0.dev1/.secrets.baseline +127 -0
- pinky_tools-0.1.0.dev1/AGENT.md +80 -0
- pinky_tools-0.1.0.dev1/CONTEXT.md +18 -0
- pinky_tools-0.1.0.dev1/LICENSE +21 -0
- pinky_tools-0.1.0.dev1/PKG-INFO +84 -0
- pinky_tools-0.1.0.dev1/README.md +31 -0
- pinky_tools-0.1.0.dev1/docs/adr/0001-click-over-argparse.md +18 -0
- pinky_tools-0.1.0.dev1/docs/adr/0002-i18n-env-var-from-day-one.md +25 -0
- pinky_tools-0.1.0.dev1/docs/adr/0003-export-last-select-wins.md +21 -0
- pinky_tools-0.1.0.dev1/docs/adr/0004-export-col-transform-not-in-yaml.md +21 -0
- pinky_tools-0.1.0.dev1/docs/adr/0005-export-queries-path-convention.md +26 -0
- pinky_tools-0.1.0.dev1/docs/explanation/design.md +59 -0
- pinky_tools-0.1.0.dev1/docs/explanation/features.md +115 -0
- pinky_tools-0.1.0.dev1/docs/index.md +20 -0
- pinky_tools-0.1.0.dev1/docs/reference/generated/api/readme.md +5 -0
- pinky_tools-0.1.0.dev1/docs/reference/generated/api/regression.md +5 -0
- pinky_tools-0.1.0.dev1/docs/reference/generated/api/run.md +5 -0
- pinky_tools-0.1.0.dev1/docs/reference/generated/api/validate_name.md +5 -0
- pinky_tools-0.1.0.dev1/mkdocs.dev.yml +3 -0
- pinky_tools-0.1.0.dev1/mkdocs.yml +36 -0
- pinky_tools-0.1.0.dev1/pyproject.toml +97 -0
- pinky_tools-0.1.0.dev1/scripts/hooks/check_forbidden_keywords.py +76 -0
- pinky_tools-0.1.0.dev1/scripts/hooks/check_snowpark_api.py +160 -0
- pinky_tools-0.1.0.dev1/scripts/hooks/check_typed_api.py +140 -0
- pinky_tools-0.1.0.dev1/scripts/hooks/check_zws.py +39 -0
- pinky_tools-0.1.0.dev1/src/pinky_tools/__init__.py +1 -0
- pinky_tools-0.1.0.dev1/src/pinky_tools/readme.py +1 -0
- pinky_tools-0.1.0.dev1/src/pinky_tools/regression.py +1 -0
- pinky_tools-0.1.0.dev1/src/pinky_tools/run.py +1 -0
- pinky_tools-0.1.0.dev1/src/pinky_tools/validate_name.py +1 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, develop]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, develop]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
ci:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
env:
|
|
13
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python 3.11
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.11"
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: pip install -e ".[dev]"
|
|
25
|
+
|
|
26
|
+
- name: Lint
|
|
27
|
+
run: ruff check src/ scripts/
|
|
28
|
+
|
|
29
|
+
- name: Format check
|
|
30
|
+
run: ruff format --check src/ scripts/
|
|
31
|
+
|
|
32
|
+
- name: Type check
|
|
33
|
+
run: mypy src/pinky_tools/
|
|
34
|
+
|
|
35
|
+
- name: Security scan
|
|
36
|
+
run: bandit -r src/pinky_tools/ -ll
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.dev*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
env:
|
|
12
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
id-token: write # required for trusted publishing (OIDC)
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python 3.11
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.11"
|
|
24
|
+
|
|
25
|
+
- name: Install build
|
|
26
|
+
run: pip install build
|
|
27
|
+
|
|
28
|
+
- name: Build wheel and sdist
|
|
29
|
+
run: python -m build
|
|
30
|
+
|
|
31
|
+
- name: Publish to PyPI
|
|
32
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
jobs:
|
|
6
|
+
release:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
env:
|
|
9
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
id-token: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- name: Read version
|
|
16
|
+
id: version
|
|
17
|
+
run: echo "version=$(grep '^version' pyproject.toml | cut -d'"' -f2)" >> $GITHUB_OUTPUT
|
|
18
|
+
- name: Guard — no .dev version on main
|
|
19
|
+
run: |
|
|
20
|
+
if [[ "${{ steps.version.outputs.version }}" == *".dev"* ]]; then
|
|
21
|
+
echo "❌ version .dev sur main — bumper la version avant de merger"
|
|
22
|
+
exit 1
|
|
23
|
+
fi
|
|
24
|
+
- name: Create tag
|
|
25
|
+
run: |
|
|
26
|
+
git tag "v${{ steps.version.outputs.version }}"
|
|
27
|
+
git push origin "v${{ steps.version.outputs.version }}"
|
|
28
|
+
- name: Set up Python 3.11
|
|
29
|
+
uses: actions/setup-python@v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.11"
|
|
32
|
+
- name: Install build
|
|
33
|
+
run: pip install build
|
|
34
|
+
- name: Build
|
|
35
|
+
run: python -m build
|
|
36
|
+
- name: Publish to PyPI
|
|
37
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# .pre-commit-config.yaml — pinky-tools
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# Install:
|
|
6
|
+
# pip install pre-commit
|
|
7
|
+
# pre-commit install
|
|
8
|
+
# pre-commit install --hook-type commit-msg
|
|
9
|
+
#
|
|
10
|
+
# Update standard hooks:
|
|
11
|
+
# pre-commit autoupdate
|
|
12
|
+
# =============================================================================
|
|
13
|
+
default_install_hook_types: [pre-commit, commit-msg]
|
|
14
|
+
|
|
15
|
+
repos:
|
|
16
|
+
# ── Formatting: trailing spaces + newline ─────────────────────────────────
|
|
17
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
18
|
+
rev: v6.0.0
|
|
19
|
+
hooks:
|
|
20
|
+
- id: trailing-whitespace
|
|
21
|
+
- id: end-of-file-fixer
|
|
22
|
+
- id: check-yaml
|
|
23
|
+
- id: check-toml
|
|
24
|
+
- id: check-merge-conflict
|
|
25
|
+
- id: debug-statements
|
|
26
|
+
|
|
27
|
+
# ── Formatting: Markdown ──────────────────────────────────────────────────
|
|
28
|
+
- repo: local
|
|
29
|
+
hooks:
|
|
30
|
+
- id: mdformat
|
|
31
|
+
name: mdformat
|
|
32
|
+
entry: mdformat
|
|
33
|
+
language: system
|
|
34
|
+
files: ^README\.md$
|
|
35
|
+
|
|
36
|
+
# ── Security: secrets & forbidden files ──────────────────────────────────
|
|
37
|
+
- repo: https://github.com/gitleaks/gitleaks
|
|
38
|
+
rev: v8.30.0
|
|
39
|
+
hooks:
|
|
40
|
+
- id: gitleaks
|
|
41
|
+
|
|
42
|
+
# ── Security: alternative secret detection ────────────────────────────────
|
|
43
|
+
- repo: https://github.com/Yelp/detect-secrets
|
|
44
|
+
rev: v1.5.0
|
|
45
|
+
hooks:
|
|
46
|
+
- id: detect-secrets
|
|
47
|
+
args: ["--baseline", ".secrets.baseline"]
|
|
48
|
+
exclude: ^docs/
|
|
49
|
+
|
|
50
|
+
# ── Python: ruff lint + format ────────────────────────────────────────────
|
|
51
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
52
|
+
rev: v0.15.9
|
|
53
|
+
hooks:
|
|
54
|
+
- id: ruff-check
|
|
55
|
+
args: [--no-fix]
|
|
56
|
+
- id: ruff-format
|
|
57
|
+
args: [--check]
|
|
58
|
+
|
|
59
|
+
# ── Python: type checking ─────────────────────────────────────────────────
|
|
60
|
+
- repo: local
|
|
61
|
+
hooks:
|
|
62
|
+
- id: mypy
|
|
63
|
+
name: mypy
|
|
64
|
+
entry: mypy
|
|
65
|
+
language: system
|
|
66
|
+
types: [python]
|
|
67
|
+
args: [--ignore-missing-imports]
|
|
68
|
+
files: ^src/
|
|
69
|
+
|
|
70
|
+
# ── Python: security ─────────────────────────────────────────────────────
|
|
71
|
+
- repo: local
|
|
72
|
+
hooks:
|
|
73
|
+
- id: bandit
|
|
74
|
+
name: bandit
|
|
75
|
+
entry: bandit
|
|
76
|
+
language: system
|
|
77
|
+
pass_filenames: false
|
|
78
|
+
args: [-r, src/, -ll]
|
|
79
|
+
|
|
80
|
+
# ── Zero-width spaces (copy-paste from Outlook/Teams) ────────────────────
|
|
81
|
+
- repo: local
|
|
82
|
+
hooks:
|
|
83
|
+
- id: check-zws
|
|
84
|
+
name: "[ZWS] Invisible characters (zero-width)"
|
|
85
|
+
entry: python scripts/hooks/check_zws.py
|
|
86
|
+
language: system
|
|
87
|
+
pass_filenames: true
|
|
88
|
+
|
|
89
|
+
# ── Typed API guard ──────────────────────────────────────────────────────
|
|
90
|
+
- repo: local
|
|
91
|
+
hooks:
|
|
92
|
+
- id: check-typed-api
|
|
93
|
+
name: "[TYPED-API] No raw dict/tuple/set in public annotations"
|
|
94
|
+
entry: python scripts/hooks/check_typed_api.py
|
|
95
|
+
language: system
|
|
96
|
+
types: [python]
|
|
97
|
+
files: ^src/
|
|
98
|
+
|
|
99
|
+
# ── Snowpark / Core API conventions ──────────────────────────────────────
|
|
100
|
+
- repo: local
|
|
101
|
+
hooks:
|
|
102
|
+
- id: check-snowpark-api
|
|
103
|
+
name: "[SNOWPARK-API] No session.sql(), canonical method names"
|
|
104
|
+
entry: python scripts/hooks/check_snowpark_api.py
|
|
105
|
+
language: system
|
|
106
|
+
types: [python]
|
|
107
|
+
files: ^src/
|
|
108
|
+
|
|
109
|
+
# ── Employer reference guard ──────────────────────────────────────────────
|
|
110
|
+
- repo: local
|
|
111
|
+
hooks:
|
|
112
|
+
- id: check-forbidden-keywords
|
|
113
|
+
name: "[FORBIDDEN] Employer references"
|
|
114
|
+
entry: python scripts/hooks/check_forbidden_keywords.py
|
|
115
|
+
language: system
|
|
116
|
+
pass_filenames: true
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.5.0",
|
|
3
|
+
"plugins_used": [
|
|
4
|
+
{
|
|
5
|
+
"name": "ArtifactoryDetector"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"name": "AWSKeyDetector"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "AzureStorageKeyDetector"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "Base64HighEntropyString",
|
|
15
|
+
"limit": 4.5
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "BasicAuthDetector"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "CloudantDetector"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "DiscordBotTokenDetector"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "GitHubTokenDetector"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "GitLabTokenDetector"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "HexHighEntropyString",
|
|
34
|
+
"limit": 3.0
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "IbmCloudIamDetector"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "IbmCosHmacDetector"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "IPPublicDetector"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "JwtTokenDetector"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "KeywordDetector",
|
|
50
|
+
"keyword_exclude": ""
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "MailchimpDetector"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "NpmDetector"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "OpenAIDetector"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "PrivateKeyDetector"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"name": "PypiTokenDetector"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "SendGridDetector"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "SlackDetector"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "SoftlayerDetector"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "SquareOAuthDetector"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "StripeDetector"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "TelegramBotTokenDetector"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "TwilioKeyDetector"
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"filters_used": [
|
|
90
|
+
{
|
|
91
|
+
"path": "detect_secrets.filters.allowlist.is_line_allowlisted"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies",
|
|
95
|
+
"min_level": 2
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"path": "detect_secrets.filters.heuristic.is_indirect_reference"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"path": "detect_secrets.filters.heuristic.is_likely_id_string"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"path": "detect_secrets.filters.heuristic.is_lock_file"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"path": "detect_secrets.filters.heuristic.is_potential_uuid"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"path": "detect_secrets.filters.heuristic.is_sequential_string"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"path": "detect_secrets.filters.heuristic.is_swagger_file"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"path": "detect_secrets.filters.heuristic.is_templated_secret"
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"results": {},
|
|
126
|
+
"generated_at": "2026-06-04T22:13:47Z"
|
|
127
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# AGENT.md — pinky-tools
|
|
2
|
+
*Update date : 2026-05-31 12:10*
|
|
3
|
+
|
|
4
|
+
Local dev CLI for Snowflake data engineers.
|
|
5
|
+
Part of the pinky suite.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What this repo is
|
|
10
|
+
|
|
11
|
+
`pinky-tools` is the developer-side CLI — it covers the local dev loop that
|
|
12
|
+
`pinky-provider` does not: run a stored procedure locally, generate the README
|
|
13
|
+
from AST, compare outputs across versions, and validate naming conventions.
|
|
14
|
+
|
|
15
|
+
The CLI entry point is `pinky`. See [`CONTEXT.md`](CONTEXT.md) for naming.
|
|
16
|
+
|
|
17
|
+
> **Status: design phase.** See [`docs/INDEX.md`](docs/INDEX.md) for the full design.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Repository structure (target)
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
pinky-tools/
|
|
25
|
+
├── src/
|
|
26
|
+
│ └── pinky_tools/
|
|
27
|
+
│ ├── cli.py ← click entry point
|
|
28
|
+
│ ├── run.py ← local SP runner
|
|
29
|
+
│ ├── readme.py ← README generator (AST + live enrichment)
|
|
30
|
+
│ ├── regression.py ← output comparator (CSV / XLSX)
|
|
31
|
+
│ └── validate_name.py ← naming convention validator
|
|
32
|
+
├── docs/ ← see docs/INDEX.md for the full map
|
|
33
|
+
│ ├── explanation/ ← design.md · features.md
|
|
34
|
+
│ └── adr/
|
|
35
|
+
├── tests/
|
|
36
|
+
├── pyproject.toml
|
|
37
|
+
└── AGENT.md ← this file
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Stack
|
|
43
|
+
|
|
44
|
+
- Python 3.11
|
|
45
|
+
- `click` + `rich-click` — CLI
|
|
46
|
+
- `rich` — terminal output
|
|
47
|
+
- `snowflake-snowpark-python` — session for `run` command
|
|
48
|
+
- `openpyxl` — XLSX support for `regression`
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## CLI commands
|
|
53
|
+
|
|
54
|
+
| Command | What it does |
|
|
55
|
+
|---------|-------------|
|
|
56
|
+
| `pinky run <file>` | Execute a Snowpark `.py` file against a live Snowflake connection |
|
|
57
|
+
| `pinky readme` | Generate README from Python AST extraction |
|
|
58
|
+
| `pinky regression <f1> <f2>` | Compare two output files (CSV / XLSX) |
|
|
59
|
+
| `pinky validate-name <name>` | Validate a schema/repo name against the naming convention |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Commit convention
|
|
64
|
+
|
|
65
|
+
Format: `<emoji> <type>(<scope>): <description>`
|
|
66
|
+
|
|
67
|
+
Scopes: `setup` | `cli` | `run` | `readme` | `regression` | `validate` | `docs` | `ci`
|
|
68
|
+
|
|
69
|
+
See workspace-level CLAUDE.md for the full emoji ↔ type table.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Branch strategy
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
main ← stable, PR required
|
|
77
|
+
develop ← integration, PR required from feature/*
|
|
78
|
+
feature/* ← one task = one branch
|
|
79
|
+
hotfix/* ← urgent fix from main
|
|
80
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# CONTEXT.md — pinky-tools
|
|
2
|
+
*Update date : 2026-05-31 12:10*
|
|
3
|
+
|
|
4
|
+
Single source of truth for naming in this repo.
|
|
5
|
+
|
|
6
|
+
| Term (preferred) | Avoid | Definition |
|
|
7
|
+
|---|---|---|
|
|
8
|
+
| `pinky` | `pythia`, `snowflake-tools` | CLI entry point — the `pinky <command>` invocation |
|
|
9
|
+
| `run` | `runner`, `local_runner` | Command that executes a Snowpark `.py` file against a live Snowflake connection |
|
|
10
|
+
| `readme` | `generate-readme`, `ast-readme` | Command that generates a README from Python AST extraction |
|
|
11
|
+
| `regression` | `compare`, `diff` | Command that compares two output files (CSV / XLSX) |
|
|
12
|
+
| `validate-name` | `check-name`, `name-check` | Command that validates a schema/repo name against the naming convention |
|
|
13
|
+
| SP | stored procedure | A Snowpark Python stored procedure |
|
|
14
|
+
| project | repo, pipeline | A data project following the 1-schema = 1-repo convention |
|
|
15
|
+
|
|
16
|
+
## Flagged ambiguities
|
|
17
|
+
|
|
18
|
+
- **`pinky` vs `pythia`**: the CLI entry point is `pinky`. `pythia` appears in legacy docs and the rename is being applied progressively — always use `pinky` in new code and docs.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 pinky-and-co
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pinky-tools
|
|
3
|
+
Version: 0.1.0.dev1
|
|
4
|
+
Summary: Local dev CLI for Snowflake data engineers
|
|
5
|
+
Project-URL: Homepage, https://github.com/pinky-and-co/pinky-tools
|
|
6
|
+
Project-URL: Repository, https://github.com/pinky-and-co/pinky-tools
|
|
7
|
+
Project-URL: Issues, https://github.com/pinky-and-co/pinky-tools/issues
|
|
8
|
+
Author: pinky-and-co
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 pinky-and-co
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: cli,data-engineering,snowflake,snowpark
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
35
|
+
Classifier: Topic :: Database
|
|
36
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
37
|
+
Requires-Python: >=3.11
|
|
38
|
+
Requires-Dist: click
|
|
39
|
+
Requires-Dist: openpyxl
|
|
40
|
+
Requires-Dist: rich
|
|
41
|
+
Requires-Dist: rich-click
|
|
42
|
+
Requires-Dist: snowflake-snowpark-python
|
|
43
|
+
Provides-Extra: dev
|
|
44
|
+
Requires-Dist: bandit; extra == 'dev'
|
|
45
|
+
Requires-Dist: mkdocs-material>=9.0; extra == 'dev'
|
|
46
|
+
Requires-Dist: mkdocstrings[python]>=0.25; extra == 'dev'
|
|
47
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
48
|
+
Requires-Dist: pre-commit; extra == 'dev'
|
|
49
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
50
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
51
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
53
|
+
|
|
54
|
+
# pinky-tools
|
|
55
|
+
|
|
56
|
+
*Update date : 2026-05-31 12:10*
|
|
57
|
+
|
|
58
|
+
Local dev CLI for Snowflake data engineers — run stored procedures locally, generate README docs, and validate naming conventions.
|
|
59
|
+
|
|
60
|
+
Part of the [pinky-and-co](https://github.com/pinky-and-co) suite.
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install pinky-tools
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Quick start
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pinky run resources/procedure/my_sp.py
|
|
72
|
+
pinky readme
|
|
73
|
+
pinky validate-name "financial__workday_to_altaix__compensation"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Docs
|
|
77
|
+
|
|
78
|
+
- [Design](docs/explanation/design.md)
|
|
79
|
+
- [Features & roadmap](docs/explanation/features.md)
|
|
80
|
+
- [ADRs](docs/adr/)
|
|
81
|
+
|
|
82
|
+
______________________________________________________________________
|
|
83
|
+
|
|
84
|
+
MIT License
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# pinky-tools
|
|
2
|
+
|
|
3
|
+
*Update date : 2026-05-31 12:10*
|
|
4
|
+
|
|
5
|
+
Local dev CLI for Snowflake data engineers — run stored procedures locally, generate README docs, and validate naming conventions.
|
|
6
|
+
|
|
7
|
+
Part of the [pinky-and-co](https://github.com/pinky-and-co) suite.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install pinky-tools
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pinky run resources/procedure/my_sp.py
|
|
19
|
+
pinky readme
|
|
20
|
+
pinky validate-name "financial__workday_to_altaix__compensation"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Docs
|
|
24
|
+
|
|
25
|
+
- [Design](docs/explanation/design.md)
|
|
26
|
+
- [Features & roadmap](docs/explanation/features.md)
|
|
27
|
+
- [ADRs](docs/adr/)
|
|
28
|
+
|
|
29
|
+
______________________________________________________________________
|
|
30
|
+
|
|
31
|
+
MIT License
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# ADR-0001 — click over argparse
|
|
2
|
+
Status: accepted
|
|
3
|
+
Date: 2026-05-31
|
|
4
|
+
|
|
5
|
+
## Context
|
|
6
|
+
|
|
7
|
+
The CLI commands migrated from legacy use `argparse`. `pinky-provider` had the
|
|
8
|
+
same choice and already decided on `click` (see pinky-provider ADR-0002).
|
|
9
|
+
|
|
10
|
+
## Decision
|
|
11
|
+
|
|
12
|
+
Use `click` + `rich-click` for all CLI commands — same decision as `pinky-provider`.
|
|
13
|
+
|
|
14
|
+
## Consequences
|
|
15
|
+
|
|
16
|
+
Consistent CLI experience across the suite. `rich-click` adds automatic Rich
|
|
17
|
+
formatting to help text with zero extra effort. Aligns with `pinky-provider`
|
|
18
|
+
so conventions and patterns are shared.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# ADR-0002 — i18n via env var from day one
|
|
2
|
+
Status: accepted
|
|
3
|
+
Date: 2026-05-31
|
|
4
|
+
|
|
5
|
+
## Context
|
|
6
|
+
|
|
7
|
+
CLI output strings need to be consistent and localizable. The suite is open-source
|
|
8
|
+
and may be used in both English and French contexts.
|
|
9
|
+
|
|
10
|
+
## Decision
|
|
11
|
+
|
|
12
|
+
All CLI-facing strings are defined as keyed templates in `i18n/en.py` and `i18n/fr.py`.
|
|
13
|
+
Locale is resolved in order: `locale` argument → `SNOWFLAKE_TOOLS_LOCALE` env var → `en`.
|
|
14
|
+
Unsupported locales fall back silently to `en`. Missing keys return the key itself — no crash.
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
t = get_translator() # uses env var or "en"
|
|
18
|
+
t = get_translator("fr") # force French
|
|
19
|
+
print(t("export.done", path="/tmp/out.xlsx"))
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Consequences
|
|
23
|
+
|
|
24
|
+
Zero hardcoded output strings in command implementations. Adding a new locale = adding
|
|
25
|
+
one file in `i18n/`. Applies to all commands, not just `pinky export`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# ADR-0003 — `pinky export`: last-SELECT-wins execution model
|
|
2
|
+
Status: accepted
|
|
3
|
+
Date: 2026-05-31
|
|
4
|
+
|
|
5
|
+
## Context
|
|
6
|
+
|
|
7
|
+
A `.sql` file passed to `pinky export` may contain multiple statements: session
|
|
8
|
+
variable SETs, intermediate CTEs, DML warm-ups, and a final SELECT to export.
|
|
9
|
+
Only one result is exported to xlsx.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
The last statement in the file is the one exported. All preceding statements are
|
|
14
|
+
executed for side effects (SET, DML, intermediate SELECTs). If the last statement
|
|
15
|
+
is not a SELECT, the command fails immediately with a clear error message.
|
|
16
|
+
|
|
17
|
+
## Consequences
|
|
18
|
+
|
|
19
|
+
Forces good SQL hygiene — the export query is always the last and most visible
|
|
20
|
+
thing in the file. No silent partial exports. Callers know exactly which result
|
|
21
|
+
they will get without reading the implementation.
|