Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update #1

Merged
merged 12 commits into from
Aug 2, 2024
3 changes: 2 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"ms-python.vscode-pylance",
"ms-toolsai.jupyter",
"GitHub.copilot",
"visualstudioexptteam.vscodeintellicode"
"visualstudioexptteam.vscodeintellicode",
"github.vscode-github-actions"
]
}
}
Expand Down
49 changes: 49 additions & 0 deletions .github/workflows/publish-python-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Publish Tag-Versioned Python Package

on:
push:
branches:
- main
tags:
- 'v*.*.*'

jobs:
build_and_publish:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine

- name: Check for existing dist directory
run: |
if [ -d "dist" ]; then
echo "Error: 'dist' directory already exists." >&2
exit 1
fi

- name: Build distribution
run: |
python setup.py sdist bdist_wheel

- name: Check distribution
run: |
twine check dist/*

- name: Upload distribution to PyPI
run: |
twine upload dist/*
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI }}

42 changes: 42 additions & 0 deletions .github/workflows/unittests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# .github/workflows/python-tests.yml
name: Unit Tests

on:
push:
branches:
- '*' # Trigger on push to all branches

jobs:
test:
runs-on: ubuntu-latest # The environment to run the job in

steps:
- name: Checkout code
uses: actions/checkout@v3 # Checkout the repository code

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x' # Specify the Python version to use

- name: Install dependencies
run: |
if [ -f requirements.txt ]; then
echo "requirements.txt found, installing dependencies..."
python -m pip install --upgrade pip
pip install -r requirements.txt
else
echo "requirements.txt not found, skipping dependency installation."
fi

- name: Run tests
run: |
mkdir -p test-results # Create directory for test results
python -m unittest discover -s tests -p "*test.py" | tee test-results/test_output.log
# Here, we're redirecting output to a log file in the test-results directory

- name: Upload test results
uses: actions/upload-artifact@v3
with:
name: unittest-results
path: test-results/test_output.log
15 changes: 7 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
.vscode/
__pycache__/
build
dist
*.egg-info/
*.ipynb
*temp*
.pypirc
.vscode/
__pycache__/
build
dist
*.egg-info/
*.ipynb
*temp*
211 changes: 107 additions & 104 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,104 +1,107 @@
# Swizzle Decorator

The **Swizzle Decorator** for Python enhances attribute lookup methods (`__getattr__` or `__getattribute__`) to facilitate dynamic and flexible retrieval of multiple attributes based on specified arrangements of their names. This concept is reminiscent of swizzling in computer graphics, where it allows efficient access to components of vectors or coordinates in various orders:

```python
import swizzle

@swizzle
class Vector:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z

print(Vector(1, 2, 3).yzx) # Output: (2, 3, 1)
```

## Installation
### From PyPI
```bash
pip install swizzle
```
### From GitHub
```bash
pip install git+https://github.com/janthmueller/swizzle.git
```

## Further Examples

### Using `swizzle` with `dataclass`

```python
import swizzle
from dataclasses import dataclass

@swizzle
@dataclass
class XYZ:
x: int
y: int
z: int

# Test the swizzle
xyz = XYZ(1, 2, 3)
print(xyz.yzx) # Output: (2, 3, 1)
```

### Using `swizzle` with `IntEnum`

```python
import swizzle
from enum import IntEnum

@swizzle(meta=True)
class XYZ(IntEnum):
X = 1
Y = 2
Z = 3

# Test the swizzle
print(XYZ.yxz) # Output: (<XYZ.Y: 2>, <XYZ.X: 1>, <XYZ.Z: 3>)
```
Setting the `meta` argument to `True` in the swizzle decorator extends the `getattr` behavior of the metaclass, enabling attribute swizzling directly on the class itself.

### Using `swizzle` with `NamedTuple`

```python
import swizzle
from typing import NamedTuple

@swizzle
class XYZ(NamedTuple):
x: int
y: int
z: int

# Test the swizzle
xyz = XYZ(1, 2, 3)
print(xyz.yzx) # Output: (2, 3, 1)
```


### Sequential matching
Attributes are matched from left to right, starting with the longest substring match.
```python
import swizzle

@swizzle(meta=True)
class Test:
x = 1
y = 2
z = 3
xy = 4
yz = 5
xz = 6
xyz = 7

# Test the swizzle
print(Test.xz) # Output: 6
print(Test.yz) # Output: 5
print(Test.xyyz) # Output: (4, 5)
print(Test.xyzx) # Output: (7, 1)
```

# Swizzle Decorator

The **Swizzle Decorator** for Python enhances attribute lookup methods (`__getattr__` or `__getattribute__`) to facilitate dynamic and flexible retrieval of multiple attributes based on specified arrangements of their names. This concept is reminiscent of swizzling in computer graphics, where it allows efficient access to components of vectors or coordinates in various orders:

```python
import swizzle

@swizzle
class Vector:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z

print(Vector(1, 2, 3).yzx) # Output: (2, 3, 1)
```

## Installation
### From PyPI
```bash
pip install swizzle
```
### From GitHub
```bash
pip install git+https://github.com/janthmueller/swizzle.git
```

## Further Examples

### Using `swizzle` with `dataclass`

```python
import swizzle
from dataclasses import dataclass

@swizzle
@dataclass
class XYZ:
x: int
y: int
z: int

# Test the swizzle
xyz = XYZ(1, 2, 3)
print(xyz.yzx) # Output: (2, 3, 1)
```

### Using `swizzle` with `IntEnum`

```python
import swizzle
from enum import IntEnum

@swizzle(meta=True)
class XYZ(IntEnum):
X = 1
Y = 2
Z = 3

# Test the swizzle
print(XYZ.YXZ) # Output: (<XYZ.Y: 2>, <XYZ.X: 1>, <XYZ.Z: 3>)
```
Setting the `meta` argument to `True` in the swizzle decorator extends the `getattr` behavior of the metaclass, enabling attribute swizzling directly on the class itself.

### Using `swizzle` with `NamedTuple`

```python
import swizzle
from typing import NamedTuple

@swizzle
class XYZ(NamedTuple):
x: int
y: int
z: int

# Test the swizzle
xyz = XYZ(1, 2, 3)
print(xyz.yzx) # Output: (2, 3, 1)
```


### Sequential matching
Attributes are matched from left to right, starting with the longest substring match.
```python
import swizzle

@swizzle(meta=True)
class Test:
x = 1
y = 2
z = 3
xy = 4
yz = 5
xz = 6
xyz = 7

# Test the swizzle
print(Test.xz) # Output: 6
print(Test.yz) # Output: 5
print(Test.xyyz) # Output: (4, 5)
print(Test.xyzx) # Output: (7, 1)
```

## To Do
- [ ] Add support for module-level swizzling
- [ ] Swizzle for method args (swizzle+partial)
Loading
Loading