Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .github/__init__.py
Empty file.
43 changes: 34 additions & 9 deletions .github/utils/find.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import re
import shutil
from argparse import ArgumentParser
Expand All @@ -8,16 +9,23 @@
def _create_parser():
p = ArgumentParser(
"Find and copy files",
usage="python find.py -from <from> -to <to>",
usage="python .github/utils/find.py copy -from <from> -to <to>",
description="""
Used to replace the linux find function because we need some magic that the 'find' function
doesn't provide.

Currently, only the 'copy' function is supported. During copy, the basename of the file is
kept (all the parent paths are stripped).
Currently, only the 'copy' and 'remove' function are supported. During copy,
the basename of the file is kept (all the parent paths are stripped).

When running remove, the current working directory is searched recursively for all the
files matching the pattern.
""".strip()
)

p.add_argument("action",
type=str,
help="The action to execute, currently only `copy` or `remove`".strip())

p.add_argument("-from",
type=str,
help="""
Expand All @@ -37,12 +45,15 @@ def _create_parser():
type=str,
help="Regex file pattern to match")

p.add_argument("-dry_run", action="store_true")

return p


def find_and_copy(from_folder: Path,
to_folder: Path,
pattern: Optional[str]):
pattern: Optional[str],
dry_run: bool):
if pattern is None:
pat = None
else:
Expand All @@ -53,8 +64,17 @@ def find_and_copy(from_folder: Path,
for file in Path(from_folder).rglob('*'):
if file.is_file():
if pat is None or pat.search(file.as_posix()):
print(f"Copying file '{file}' to {to_folder / file.name} ")
shutil.copy(file, to_folder / file.name)
print(f"Copying file '{file}' to {to_folder / file.name}")
if not dry_run:
shutil.copy(file, to_folder / file.name)


def find_and_remove(pattern: str, dry_run: bool):
for file in Path.cwd().rglob(pattern): # type: Path
if file.is_file():
print(f"Removing file: '{file}'")
if not dry_run:
os.remove(file)


def create_path(path: str):
Expand All @@ -68,6 +88,11 @@ def create_path(path: str):
parser = _create_parser()
args = parser.parse_args()

find_and_copy(create_path(getattr(args, 'from')),
create_path(getattr(args, 'to')),
args.pattern)
action = args.action.lower().strip()
if action == "copy":
find_and_copy(create_path(getattr(args, 'from')),
create_path(getattr(args, 'to')),
args.pattern,
args.dry_run)
elif action == "remove":
find_and_remove(args.pattern, args.dry_run)
63 changes: 63 additions & 0 deletions .github/utils/requirements.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import re
import tomllib
from pathlib import Path


def cleanup_requirements():
root = Path(__file__).parents[2]
with open(root / "pyproject.toml", "rb") as f:
py = tomllib.load(f)

req_folder = root / "requirements"
with open(req_folder / "test.txt", "w") as f:
f.write(_form_dependencies(
py['project']['dependencies'],
py['tool']['poetry']['group']['test']['dependencies'],
py['tool']['poetry']['group']['build']['dependencies'],
))

with open(req_folder / "build.txt", "w") as f:
f.write(_form_dependencies(
py['tool']['poetry']['group']['build']['dependencies'],
))

def _form_dependencies(*sections):
deps = {}
for s in sections:
new_deps = _parse_dependencies(s)
deps = new_deps | deps

items = list(deps.values())
items.append("")
return "\n".join(items)


def _parse_dependencies(dependencies: list[str] | dict[str, str]):
output = {}
if isinstance(dependencies, list):
pattern = r"([\w-]+)\s*\(([\d\s,<>=.]+)\)(?:\s*;\s*(python_version\s*(?:<|>|<=|>=|==)\s*\"\d[(?:.\d)]+\"))?"
pattern = re.compile(pattern)

for line in dependencies:
pkg, version, extras = pattern.search(line).groups()
dep = f"{pkg}{version}"
if extras:
dep = f"{dep} ; {extras}"
output[pkg] = dep

if isinstance(dependencies, dict):
for pkg, version in dependencies.items(): # type: str, str
if version.startswith("^"):
version = version[1:]
next_major = int(version.split(".")[0]) + 1
version = f">={version},<{next_major}"
else:
raise NotImplementedError
output[pkg] = f"{pkg}{version}"

return output



if __name__ == '__main__':
cleanup_requirements()
4 changes: 2 additions & 2 deletions version.py → .github/utils/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from argparse import ArgumentParser
from pathlib import Path

root = Path(__file__).parent
root = Path(__file__).parents[2]

p = ArgumentParser(
"Version updater",
usage="python version.py [major|minor|patch|0.0.0]",
usage="python .github/utils/version.py [major|minor|patch|0.0.0]",
description="""
Manage Copulae version

Expand Down
81 changes: 24 additions & 57 deletions .github/workflows/test-build-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
python-version: [ 3.9, '3.10', '3.11', '3.12' ]
python-version: [ '3.10', '3.11', '3.12', '3.13' ]

steps:
- name: Checkout Repository
Expand Down Expand Up @@ -49,7 +49,7 @@ jobs:
if: steps.pip-cache.outputs.cache-hit != 'true'
run: |
python -m pip install --upgrade pip
pip install -r build-requirements.txt
pip install -r requirements/test.txt

- name: Build Extensions
run: python setup.py build_ext --inplace
Expand All @@ -73,15 +73,15 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Setup Python 3.10
- name: Setup Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.10'
python-version: '3.11'

- name: Package source distribution
run: |
python -m pip install --upgrade pip
pip install -r build-requirements.txt
pip install -r requirements/build.txt
python setup.py sdist

- name: List items
Expand All @@ -92,7 +92,7 @@ jobs:
- name: Place distribution in artifacts folder
uses: actions/upload-artifact@v4
with:
name: bdist
name: sdist
path: dist/*.tar.gz
if-no-files-found: error

Expand All @@ -108,18 +108,18 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Setup Python 3.10
- name: Setup Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.10'
python-version: '3.11'

- name: Build BDist Package
env:
# specify python environments. Skip 32-bit builds
CIBW_BUILD: cp39-* cp310-* cp311-* cp312-*
CIBW_BUILD: cp39-* cp310-* cp311-* cp312-* cp313-*
CIBW_SKIP: "*-win32 *-manylinux_i686 *-musllinux_*"
# install dependencies, these are the minimum dependencies for building the wheels
CIBW_BEFORE_BUILD: pip install numpy cython scipy
CIBW_BEFORE_BUILD: pip install -r requirements/build.txt
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
run: |
python -m pip install --upgrade pip
Expand Down Expand Up @@ -147,7 +147,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
python-version: [ 3.9, '3.10', '3.11', '3.12' ]
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
# ext: [ tar.gz, whl ]
ext: [ whl ]

Expand Down Expand Up @@ -191,20 +191,24 @@ jobs:
# if we can import this, all should be gucci
python -c "import copulae"

deploy-test:
name: Deploy packages to TestPyPI
deploy:
name: Deploy packages
runs-on: ubuntu-latest
needs: install-package
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
permissions:
id-token: write
contents: read

steps:
- name: Setup Python 3.10
- name: Setup Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.10'
python-version: '3.11'

- name: Install twine
run: pip install twine
run: |
pip install twine
pip install -U packaging

- name: Checkout utilities
uses: actions/checkout@v4
Expand All @@ -222,49 +226,12 @@ jobs:
run: |
mkdir files
ls -ltR
python .github/utils/find.py -from dist -to files -pattern "(.tar.gz|.whl)$"
python .github/utils/find.py copy -from dist -to files -pattern "(.tar.gz|.whl)$"

- name: Upload packages to testpypi
env:
TWINE_USERNAME: ${{ secrets.PYPI_TEST_TOKEN_NAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_TEST_API_TOKEN }}
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
run: python -m twine upload --skip-existing --repository testpypi files/* --verbose

deploy:
name: Deploy packages to PyPI
runs-on: ubuntu-latest
needs: install-package
if: startsWith(github.ref, 'refs/tags/')

steps:
- name: Setup Python 3.10
uses: actions/setup-python@v5
with:
python-version: '3.10'

- name: Install twine
run: pip install twine

- name: Checkout utilities
uses: actions/checkout@v4
with:
sparse-checkout: |
.github/utils
sparse-checkout-cone-mode: false

- name: Retrieve packages
uses: actions/download-artifact@v4
with:
path: dist

- name: Find and copy packages to files/
run: |
mkdir files
ls -ltR
python .github/utils/find.py -from dist -to files -pattern "(.tar.gz|.whl)$"

- name: Upload packages to pypi
env:
TWINE_USERNAME: ${{ secrets.PYPI_PROD_TOKEN_NAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PROD_API_TOKEN }}
if: startsWith(github.ref, 'refs/tags/')
run: python -m twine upload --skip-existing files/* --verbose
15 changes: 9 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,33 @@ all: dist


dist: wheel clean
python setup.py sdist
poetry run python setup.py sdist


wheel: clean ext
python setup.py bdist_wheel
poetry run python setup.py bdist_wheel


ext:
python setup.py build_ext --inplace
poetry run python setup.py build_ext --inplace


test:
python -m pytest tests/
poetry run python -m pytest tests/


clean:
rm -rf build/ .pytest_cache/ *.egg-info dist/ __pycache__/ dist/

# delete cython linker files
find . -type f -name "*.pyd" -print -delete
poetry run python .github/utils/find.py remove -pattern *.pyd

# delete pytest coverage file
find . -type f -name "*.coverage" -print -delete
poetry run python .github/utils/find.py remove -pattern *.coverage

linux:
rm -rf dist/*
docker container run --rm -v $(CURDIR):/copulae danielbok/manylinux1 /copulae/manylinux-build.sh

req:
poetry run python .github\utils\requirements.py
23 changes: 0 additions & 23 deletions Pipfile

This file was deleted.

Loading
Loading