Skip to content

Commit 60bdb40

Browse files
Bissbertclaude
andcommitted
feat: add PyPI publishing workflow and update package configuration
- Add pypi-publish.yml workflow for trusted publishing - Rename package to gemmology-cdl-parser - Fix lint errors and improve code quality Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent e97f60a commit 60bdb40

9 files changed

Lines changed: 286 additions & 269 deletions

File tree

.github/workflows/pypi-publish.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Reusable workflow: Publish to PyPI on release
2+
# Usage: Copy to each Python package repo's .github/workflows/
3+
4+
name: Publish to PyPI
5+
6+
on:
7+
release:
8+
types: [published]
9+
10+
jobs:
11+
publish:
12+
runs-on: ubuntu-latest
13+
environment: pypi
14+
permissions:
15+
id-token: write # For trusted publishing
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Set up Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: '3.11'
24+
25+
- name: Install build tools
26+
run: pip install build
27+
28+
- name: Build package
29+
run: python -m build
30+
31+
- name: Publish to PyPI
32+
uses: pypa/gh-action-pypi-publish@release/v1
33+
# Uses trusted publishing - no token needed if configured
34+
# Fallback to token-based auth:
35+
# with:
36+
# password: ${{ secrets.PYPI_TOKEN }}
37+
38+
- name: Create GitHub Release Assets
39+
env:
40+
GH_TOKEN: ${{ github.token }}
41+
run: |
42+
gh release upload ${{ github.event.release.tag_name }} dist/*

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[project]
2-
name = "cdl-parser"
2+
name = "gemmology-cdl-parser"
33
version = "1.0.0"
44
description = "Crystal Description Language (CDL) parser for crystallographic visualization"
55
readme = "README.md"

src/cdl_parser/__init__.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,6 @@
2727
__email__ = "fabian@gemmology.dev"
2828

2929
# Core parsing functions
30-
from .parser import parse_cdl, validate_cdl
31-
32-
# Data classes
33-
from .models import (
34-
CrystalDescription,
35-
CrystalForm,
36-
MillerIndex,
37-
Modification,
38-
TwinSpec,
39-
)
40-
41-
# Exceptions
42-
from .exceptions import CDLError, ParseError, ValidationError
43-
4430
# Constants
4531
from .constants import (
4632
ALL_POINT_GROUPS,
@@ -53,8 +39,20 @@
5339
TWIN_TYPES,
5440
)
5541

42+
# Exceptions
43+
from .exceptions import CDLError, ParseError, ValidationError
44+
45+
# Data classes
46+
from .models import (
47+
CrystalDescription,
48+
CrystalForm,
49+
MillerIndex,
50+
Modification,
51+
TwinSpec,
52+
)
53+
5654
# Lexer/Parser internals (for advanced use)
57-
from .parser import Lexer, Parser, Token, TokenType
55+
from .parser import Lexer, Parser, Token, TokenType, parse_cdl, validate_cdl
5856

5957
__all__ = [
6058
# Version

src/cdl_parser/cli.py

Lines changed: 16 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import argparse
88
import sys
9-
from typing import Optional
109

1110
from . import __version__
1211
from .constants import (
@@ -22,8 +21,8 @@
2221
def create_parser() -> argparse.ArgumentParser:
2322
"""Create the argument parser."""
2423
parser = argparse.ArgumentParser(
25-
prog='cdl',
26-
description='Crystal Description Language (CDL) Parser',
24+
prog="cdl",
25+
description="Crystal Description Language (CDL) Parser",
2726
formatter_class=argparse.RawDescriptionHelpFormatter,
2827
epilog="""
2928
Examples:
@@ -32,62 +31,33 @@ def create_parser() -> argparse.ArgumentParser:
3231
%(prog)s validate "hexagonal[6/mmm]:{10-10} + {0001}"
3332
%(prog)s --list-point-groups
3433
%(prog)s --list-systems
35-
"""
34+
""",
3635
)
3736

38-
parser.add_argument(
39-
'--version',
40-
action='version',
41-
version=f'%(prog)s {__version__}'
42-
)
37+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
4338

4439
parser.add_argument(
45-
'command',
46-
nargs='?',
47-
choices=['parse', 'validate'],
48-
help='Command to execute'
40+
"command", nargs="?", choices=["parse", "validate"], help="Command to execute"
4941
)
5042

51-
parser.add_argument(
52-
'cdl',
53-
nargs='?',
54-
help='CDL string to parse/validate'
55-
)
43+
parser.add_argument("cdl", nargs="?", help="CDL string to parse/validate")
5644

5745
parser.add_argument(
58-
'--list-point-groups',
59-
action='store_true',
60-
help='List all point groups by system'
46+
"--list-point-groups", action="store_true", help="List all point groups by system"
6147
)
6248

63-
parser.add_argument(
64-
'--list-systems',
65-
action='store_true',
66-
help='List all crystal systems'
67-
)
49+
parser.add_argument("--list-systems", action="store_true", help="List all crystal systems")
6850

69-
parser.add_argument(
70-
'--list-forms',
71-
action='store_true',
72-
help='List all named forms'
73-
)
51+
parser.add_argument("--list-forms", action="store_true", help="List all named forms")
7452

75-
parser.add_argument(
76-
'--list-twins',
77-
action='store_true',
78-
help='List all twin laws'
79-
)
53+
parser.add_argument("--list-twins", action="store_true", help="List all twin laws")
8054

81-
parser.add_argument(
82-
'--json',
83-
action='store_true',
84-
help='Output parsed result as JSON'
85-
)
55+
parser.add_argument("--json", action="store_true", help="Output parsed result as JSON")
8656

8757
return parser
8858

8959

90-
def main(args: Optional[list] = None) -> int:
60+
def main(args: list | None = None) -> int:
9161
"""Main entry point for the CLI."""
9262
parser = create_parser()
9363
parsed_args = parser.parse_args(args)
@@ -127,12 +97,13 @@ def main(args: Optional[list] = None) -> int:
12797
parser.print_help()
12898
return 1
12999

130-
if parsed_args.command == 'parse':
100+
if parsed_args.command == "parse":
131101
try:
132102
desc = parse_cdl(parsed_args.cdl)
133103

134104
if parsed_args.json:
135105
import json
106+
136107
print(json.dumps(desc.to_dict(), indent=2))
137108
else:
138109
print("Parsed successfully!")
@@ -153,7 +124,7 @@ def main(args: Optional[list] = None) -> int:
153124
print(f"Parse error: {e}", file=sys.stderr)
154125
return 1
155126

156-
elif parsed_args.command == 'validate':
127+
elif parsed_args.command == "validate":
157128
is_valid, error = validate_cdl(parsed_args.cdl)
158129
if is_valid:
159130
print("Valid CDL string")
@@ -165,5 +136,5 @@ def main(args: Optional[list] = None) -> int:
165136
return 0
166137

167138

168-
if __name__ == '__main__':
139+
if __name__ == "__main__":
169140
sys.exit(main())

0 commit comments

Comments
 (0)