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

use uv and hatchling #552

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
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
37 changes: 25 additions & 12 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ jobs:
arch: [x64] # x86 unsupported by MicroMamba
os: [ubuntu-latest, windows-latest, macos-latest]
jlversion: ['1','1.6']

steps:
- uses: actions/checkout@v2

- name: Set up Julia ${{ matrix.jlversion }}
uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.jlversion }}
arch: ${{ matrix.arch }}

- uses: actions/cache@v1
env:
cache-name: cache-artifacts
Expand All @@ -37,19 +40,24 @@ jobs:
${{ runner.os }}-test-${{ env.cache-name }}-
${{ runner.os }}-test-
${{ runner.os }}-

- name: Build package
uses: julia-actions/julia-buildpkg@v1

- name: Run tests
uses: julia-actions/julia-runtest@v1
env:
JULIA_DEBUG: PythonCall
JULIA_NUM_THREADS: '2'

- name: Process coverage
uses: julia-actions/julia-processcoverage@v1

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

python:
name: Test (${{ matrix.os }}, python ${{ matrix.pyversion }})
runs-on: ${{ matrix.os }}
Expand All @@ -58,33 +66,38 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
pyversion: ["3.x", "3.8"]

steps:
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.pyversion }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.pyversion }}

- name: Set up Julia
uses: julia-actions/setup-julia@v1
with:
version: '1'

- name: Set up UV
uses: astral-sh/setup-uv@v2

- name: Use dev Julia dependencies
run: cp pysrc/juliacall/juliapkg-dev.json pysrc/juliacall/juliapkg.json

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest pytest-cov nbval numpy
cp pysrc/juliacall/juliapkg-dev.json pysrc/juliacall/juliapkg.json
pip install -e .
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --ignore=F821 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
run: uv sync

- name: Lint with ruff
run: uv run ruff check

- name: Run tests
run: |
pytest -s --nbval --cov=pysrc ./pytest/
uv run pytest -s --nbval --cov=pysrc ./pytest/
env:
PYTHON_JULIACALL_THREADS: '2'

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
env:
Expand Down
6 changes: 4 additions & 2 deletions examples/flux.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
"metadata": {},
"outputs": [],
"source": [
"import numpy as np, matplotlib.pyplot as plt\n",
"from juliacall import Main as jl, convert as jlconvert"
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"from juliacall import Main as jl\n",
"from juliacall import convert as jlconvert"
]
},
{
Expand Down
27 changes: 17 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "juliacall"
Expand All @@ -10,17 +10,24 @@ readme = { file = "README.md", content-type = "text/markdown" }
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent"
"Operating System :: OS Independent",
]
requires-python = ">=3.8"
dependencies = ["juliapkg ~=0.1.8"]

[tool.setuptools]
zip-safe = false
[tool.hatch.build.targets.wheel]
packages = ["pysrc/juliacall"]

[tool.setuptools.packages.find]
where = ["pysrc"]
include = ["juliacall"]
[tool.uv]
dev-dependencies = [
"ruff",
"pytest",
"pytest-cov",
"nbval",
"numpy",
"numpy ~=2.0; python_version >= '3.10'",
]

[tool.setuptools.package-data]
"juliacall" = ["*.json", "*.jl"]
[tool.ruff.lint]
select = ["F", "E", "W", "I"]
ignore = ["E501", "E731"]
18 changes: 9 additions & 9 deletions pysrc/juliacall/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def newmodule(name):
"A new module with the given name."
global _newmodule
if _newmodule is None:
_newmodule = Main.seval("name -> (n1=Symbol(name); n2=gensym(n1); Main.@eval(module $n2; module $n1; end; end); Main.@eval $n2.$n1)")
_newmodule = Main.seval("name -> (n1=Symbol(name); n2=gensym(n1); Main.@eval(module $n2; module $n1; end; end); Main.@eval $n2.$n1)") # noqa: F821
return _newmodule(name)

_convert = None
Expand All @@ -18,15 +18,15 @@ def convert(T, x):
"Convert x to a Julia T."
global _convert
if _convert is None:
_convert = PythonCall.JlWrap.seval("pyjlcallback((T,x)->pyjl(pyconvert(pyjlvalue(T)::Type,x)))")
_convert = PythonCall.JlWrap.seval("pyjlcallback((T,x)->pyjl(pyconvert(pyjlvalue(T)::Type,x)))") # noqa: F821
return _convert(T, x)

def interactive(enable=True):
"Allow the Julia event loop to run in the background of the Python REPL."
if enable:
PythonCall.Compat._set_python_input_hook()
PythonCall.Compat._set_python_input_hook() # noqa: F821
else:
PythonCall.Compat._unset_python_input_hook()
PythonCall.Compat._unset_python_input_hook() # noqa: F821

class JuliaError(Exception):
"An error arising in Julia code."
Expand All @@ -36,9 +36,9 @@ def __str__(self):
e = self.exception
b = self.backtrace
if b is None:
return Base.sprint(Base.showerror, e)
return Base.sprint(Base.showerror, e) # noqa: F821
else:
return Base.sprint(Base.showerror, e, b)
return Base.sprint(Base.showerror, e, b) # noqa: F821
@property
def exception(self):
return self.args[0]
Expand All @@ -50,10 +50,10 @@ def backtrace(self):

def init():
import atexit
import os
import ctypes as c
import sys
import os
import subprocess
import sys
import warnings

# importing pytorch before juliacall sometimes causes segfaults. TODO: remove
Expand Down Expand Up @@ -241,7 +241,7 @@ def jlstr(x):
CONFIG['inited'] = True

if CONFIG['opt_handle_signals'] is None:
if Base.Threads.nthreads() > 1:
if Base.Threads.nthreads() > 1: # noqa: F821
# a warning to help multithreaded users
# TODO: should we set PYTHON_JULIACALL_HANDLE_SIGNALS=yes whenever PYTHON_JULIACALL_THREADS != 1?
warnings.warn(
Expand Down
5 changes: 3 additions & 2 deletions pysrc/juliacall/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
import io
import os
import sys

from . import newmodule, Base
from importlib.machinery import ModuleSpec, SourceFileLoader

from . import Base, newmodule


class Finder:
def __init__(self, jlext='.jl', pyext='.py'):
self.jlext = jlext
Expand Down
8 changes: 5 additions & 3 deletions pysrc/juliacall/ipython.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@
- Calling Julia's 'display(x)' function will display 'x' in IPython.
"""

from IPython.core.magic import Magics, magics_class, line_cell_magic
from . import Main, PythonCall
from IPython.core.magic import Magics, line_cell_magic, magics_class

import __main__

from . import Main, PythonCall

_set_var = Main.seval("(k, v) -> @eval $(Symbol(k)) = $v")
_get_var = Main.seval("k -> hasproperty(Main, Symbol(k)) ? PythonCall.pyjlraw(getproperty(Main, Symbol(k))) : nothing")
_egal = Main.seval("===")

@magics_class
class JuliaMagics(Magics):

@line_cell_magic
def julia(self, line, cell=None):
# parse the line and cell into code and variables
Expand Down
3 changes: 2 additions & 1 deletion pysrc/juliacall/matplotlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
Minimal matplotlib backend which shows plots using Julia's display mechanism.
"""

from matplotlib.backend_bases import Gcf, FigureManagerBase
from matplotlib.backend_bases import FigureManagerBase, Gcf
from matplotlib.backends.backend_agg import FigureCanvasAgg

from juliacall import Base as jl

FigureCanvas = FigureCanvasAgg
Expand Down
3 changes: 3 additions & 0 deletions pytest/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
def test_import():
import juliacall

juliacall


def test_newmodule():
import juliacall
Expand Down Expand Up @@ -123,6 +125,7 @@ def test_call_nogil(yld, raw):
"""Tests that we can execute Julia code in parallel by releasing the GIL."""
from concurrent.futures import ThreadPoolExecutor, wait
from time import time

from juliacall import Main as jl

# julia implementation of sleep which unlocks the GIL
Expand Down
6 changes: 3 additions & 3 deletions src/C/find_libpython.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from __future__ import print_function, absolute_import
from __future__ import absolute_import, print_function

from logging import getLogger
import ctypes.util
import functools
import os
import sys
import sysconfig
from logging import getLogger

logger = getLogger("find_libpython")

Expand Down Expand Up @@ -97,7 +97,7 @@ def _linked_libpython_windows():
"""
Based on: https://stackoverflow.com/a/16659821
"""
from ctypes.wintypes import HANDLE, LPWSTR, DWORD
from ctypes.wintypes import DWORD, HANDLE, LPWSTR

GetModuleFileName = ctypes.windll.kernel32.GetModuleFileNameW
GetModuleFileName.argtypes = [HANDLE, LPWSTR, DWORD]
Expand Down
Loading
Loading