Skip to content

Commit 890bbe0

Browse files
authored
feat: implement optional dependencies and modernize packaging (issue #96) (#119)
## Description Implements optional dependencies and modernizes packaging for the project. Closes #96 ## Changes - Implement optional dependencies - Modernize packaging configuration ## Type of change - [x] New feature - [x] Enhancement
1 parent 3a7450f commit 890bbe0

5 files changed

Lines changed: 205 additions & 35 deletions

File tree

.github/workflows/publish-pypi.yml

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: publish-pypi
2+
3+
on:
4+
release:
5+
types: [published]
6+
workflow_dispatch:
7+
inputs:
8+
upload:
9+
description: 'Upload to PyPI'
10+
required: false
11+
default: 'true'
12+
13+
jobs:
14+
update-version:
15+
runs-on: ubuntu-latest
16+
permissions:
17+
contents: write
18+
if: github.event_name == 'release'
19+
20+
steps:
21+
- uses: actions/checkout@v5
22+
with:
23+
ref: main
24+
25+
- name: Extract version from tag
26+
id: version
27+
run: |
28+
VERSION=${{ github.event.release.tag_name }}
29+
VERSION=${VERSION#v} # Remove 'v' prefix if present
30+
echo "version=$VERSION" >> $GITHUB_OUTPUT
31+
32+
- name: Update pyproject.toml
33+
run: |
34+
sed -i 's/version = "[^"]*"/version = "${{ steps.version.outputs.version }}"/' pyproject.toml
35+
36+
- name: Commit and push version update
37+
run: |
38+
git config user.name "github-actions[bot]"
39+
git config user.email "github-actions[bot]@users.noreply.github.com"
40+
git add pyproject.toml
41+
git commit -m "chore: bump version to ${{ steps.version.outputs.version }}"
42+
git push origin main
43+
44+
build:
45+
needs: update-version
46+
runs-on: ubuntu-latest
47+
48+
steps:
49+
- uses: actions/checkout@v5
50+
51+
- name: Set up Python
52+
uses: actions/setup-python@v6
53+
with:
54+
python-version: '3.11'
55+
56+
- name: Install build dependencies
57+
run: |
58+
python -m pip install --upgrade pip
59+
pip install build setuptools wheel
60+
61+
- name: Build distribution
62+
run: python -m build
63+
64+
- name: Upload build artifacts
65+
uses: actions/upload-artifact@v4
66+
with:
67+
name: distribution
68+
path: dist/
69+
70+
publish:
71+
needs: build
72+
runs-on: ubuntu-latest
73+
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.upload == 'true')
74+
75+
steps:
76+
- uses: actions/checkout@v5
77+
78+
- name: Download build artifacts
79+
uses: actions/download-artifact@v4
80+
with:
81+
name: distribution
82+
path: dist/
83+
84+
- name: Set up Python
85+
uses: actions/setup-python@v6
86+
with:
87+
python-version: '3.11'
88+
89+
- name: Install Twine
90+
run: pip install twine
91+
92+
- name: Publish to PyPI
93+
env:
94+
TWINE_USERNAME: __token__
95+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
96+
run: twine upload dist/* --skip-existing
97+
98+
- name: Create release note
99+
if: github.event_name == 'release'
100+
run: |
101+
echo "✅ Package published to PyPI successfully!"
102+
echo "Version: ${{ github.event.release.tag_name }}"
103+
echo "PyPI URL: https://pypi.org/project/struct/"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ __pycache__
55
*.log
66
example_project/
77
build/*
8+
dist/
89

910
# MkDocs generated documentation
1011
site/docs/

pyproject.toml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
[build-system]
2+
requires = ["setuptools>=65.0", "wheel"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "struct"
7+
version = "1.0.0"
8+
description = "A structured data processing tool"
9+
readme = "README.md"
10+
license = {text = "MIT"}
11+
authors = [{name = "httpdss"}]
12+
classifiers = [
13+
"Development Status :: 4 - Beta",
14+
"Intended Audience :: Developers",
15+
"License :: OSI Approved :: MIT License",
16+
"Programming Language :: Python :: 3",
17+
"Programming Language :: Python :: 3.8",
18+
"Programming Language :: Python :: 3.9",
19+
"Programming Language :: Python :: 3.10",
20+
"Programming Language :: Python :: 3.11",
21+
"Programming Language :: Python :: 3.12",
22+
]
23+
requires-python = ">=3.8"
24+
keywords = ["data", "structure", "processing"]
25+
26+
dependencies = [
27+
"PyYAML>=6.0",
28+
"requests>=2.28.0",
29+
"openai>=1.0.0",
30+
"python-dotenv>=0.21.0",
31+
"jinja2>=3.1.0",
32+
"PyGithub>=1.58.0",
33+
"shtab>=1.6.0",
34+
"colorlog>=6.7.0",
35+
"pydantic-ai>=0.1.0",
36+
"fastmcp>=2.0.0",
37+
]
38+
39+
[project.optional-dependencies]
40+
s3 = [
41+
"boto3>=1.26.0",
42+
]
43+
gcs = [
44+
"google-cloud-storage>=2.10.0",
45+
"google-api-core>=2.11.0",
46+
]
47+
cloud = [
48+
"struct[s3]",
49+
"struct[gcs]"
50+
]
51+
dev = [
52+
"pytest>=7.0.0",
53+
"pytest-cov>=4.0.0",
54+
"black>=22.0.0",
55+
"flake8>=4.0.0",
56+
"mypy>=0.990",
57+
]
58+
59+
[project.urls]
60+
Homepage = "https://github.com/httpdss/struct"
61+
Repository = "https://github.com/httpdss/struct.git"
62+
63+
[project.scripts]
64+
struct = "struct_module.main:main"
65+
66+
[tool.setuptools]
67+
include-package-data = true
68+
69+
[tool.setuptools.packages.find]
70+
where = ["."] # Look for packages in root directory
71+
include = ["struct_module*"]
72+
73+
[tool.setuptools.package-data]
74+
struct_module = ["contribs/*.yaml"]

requirements.txt

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1-
PyYAML
2-
requests
3-
openai
4-
python-dotenv
5-
jinja2
6-
PyGithub
7-
shtab
8-
colorlog
9-
boto3
10-
google-cloud
11-
google-api-core
12-
cachetools
13-
pydantic-ai
14-
fastmcp>=2.0
1+
# Core dependencies (always installed)
2+
PyYAML>=6.0
3+
requests>=2.28.0
4+
openai>=1.0.0
5+
python-dotenv>=0.21.0
6+
jinja2>=3.1.0
7+
PyGithub>=1.58.0
8+
shtab>=1.6.0
9+
colorlog>=6.7.0
10+
pydantic-ai>=0.1.0
11+
fastmcp>=2.0.0
12+
13+
# Optional: AWS S3 support
14+
# Install with: pip install struct[s3]
15+
# boto3>=1.26.0
16+
17+
# Optional: Google Cloud Storage support
18+
# Install with: pip install struct[gcs]
19+
# google-cloud-storage>=2.10.0
20+
# google-api-core>=2.11.0
21+
22+
# Optional: Both cloud providers
23+
# Install with: pip install struct[cloud]

setup.py

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,5 @@
1-
from setuptools import setup, find_packages
1+
# This file is maintained only for backwards compatibility.
2+
# Configuration is now in pyproject.toml (PEP 517/518).
3+
from setuptools import setup
24

3-
def parse_requirements(filename):
4-
with open(filename, 'r') as file:
5-
lines = file.readlines()
6-
return [line.strip() for line in lines if line and not line.startswith('#')]
7-
8-
setup(
9-
name='struct',
10-
version='1.0.0',
11-
packages=find_packages(),
12-
install_requires=parse_requirements('requirements.txt'),
13-
entry_points={
14-
'console_scripts': [
15-
'struct = struct_module.main:main',
16-
],
17-
},
18-
include_package_data=True,
19-
package_data={
20-
'': ['struct_module/contribs/*.yaml'],
21-
},
22-
)
5+
setup()

0 commit comments

Comments
 (0)