Skip to content

Package binary as a Python wheel #229

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

Open
wants to merge 10 commits into
base: devel
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
26 changes: 26 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM python

USER root
WORKDIR /
RUN git clone https://github.com/yaml/yamlscript
WORKDIR /yamlscript
RUN make build

RUN pip install fmtr.tools[debug] setuptools

COPY . .
WORKDIR /yamlscript/python


RUN make dist
WORKDIR /tmp

RUN pip uninstall yamlscript -y
RUN pip install /yamlscript/python/dist/yamlscript-*.whl
RUN bash -c "ys-py-show-info > bdist_wheel.info.txt"

RUN pip install /yamlscript/python/dist/yamlscript-0.1.96.tar.gz
RUN bash -c "export LD_LIBRARY_PATH=/yamlscript/libyamlscript/lib && ys-py-show-info > sdist.info.txt"


CMD sleep infinity
15 changes: 9 additions & 6 deletions python/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,20 @@ pkg-test: venv
tar xzf dist/yamlscript-*.tar.gz
cat yamlscript-*/PKG-INFO



dist: venv MANIFEST.in .long_description.md
( \
$(VENV) && \
$(PYTHON) setup.py sdist \
)
$(VENV) && \
$(PYTHON) setup.py sdist && \
cp $(LIBYS_SO_FQNP) ./lib/yamlscript/ && \
$(PYTHON) setup.py bdist_wheel

release: publish

publish: dist
( \
$(VENV) && \
twine upload --verbose --repository yamlscript dist/yamlscript-*.tar.gz \
twine upload --verbose --repository yamlscript dist/yamlscript-*.tar.gz dist/yamlscript-*.whl \
)

clean::
Expand All @@ -72,7 +74,8 @@ $(PYTHON_VENV):
pip install \
pytest \
pyyaml \
twine
twine \
setuptools

MANIFEST.in:
echo 'include ReadMe.md' > $@
Expand Down
42 changes: 38 additions & 4 deletions python/lib/yamlscript/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,25 @@
# This value is automatically updated by 'make bump'.
# The version number is used to find the correct shared library file.
# We currently only support binding to an exact version of libyamlscript.
NAME = 'yamlscript'
yamlscript_version = '0.1.96'

import os, sys
import ctypes
import json
import os
import sys
from pathlib import Path

# Require Python 3.6 or greater:
assert sys.version_info >= (3, 6), \
"Python 3.6 or greater required for 'yamlscript'."

# Find the libyamlscript shared library file path:
def find_libyamlscript_path():

def get_libyamlscript_name():
# We currently only support platforms that GraalVM supports.
# And Windows is not yet implemented...
# Confirm platform and determine file extension:

if sys.platform == 'linux':
so = 'so'
elif sys.platform == 'darwin':
Expand All @@ -44,6 +48,17 @@ def find_libyamlscript_path():
libyamlscript_name = \
"libyamlscript.%s.%s" % (so, yamlscript_version)

return libyamlscript_name

# Find the libyamlscript shared library file path:
def find_libyamlscript_path():
libyamlscript_name = get_libyamlscript_name()

# First check for shared library in bindings directory, in case of binary wheel distribution.
path = (Path(__file__).parent / libyamlscript_name).absolute()
if path.exists():
return str(path)

# Use LD_LIBRARY_PATH to find libyamlscript shared library, or default to
# '/usr/local/lib' (where it is installed by default):
ld_library_path = os.environ.get('LD_LIBRARY_PATH')
Expand All @@ -69,7 +84,8 @@ def find_libyamlscript_path():
return libyamlscript_path

# Load libyamlscript shared library:
libyamlscript = ctypes.CDLL(find_libyamlscript_path())
libyamlscript_path = find_libyamlscript_path()
libyamlscript = ctypes.CDLL(libyamlscript_path)

# Create binding to 'load_ys_to_json' function:
load_ys_to_json = libyamlscript.load_ys_to_json
Expand Down Expand Up @@ -138,3 +154,21 @@ def __del__(self):
rc = libyamlscript.graal_tear_down_isolate(self.isolatethread)
if rc != 0:
raise Exception("Failed to tear down isolate")


def show_info():
"""

Show YAMLScript package info for debugging purposes

"""
from textwrap import dedent
info = f"""
{yamlscript_version=}
{sys.platform=}
{libyamlscript_path=}
{YAMLScript().load("inc: 41")=}
{YAMLScript().load("!YS-v0\ninc: 41")=}
"""
info = dedent(info).strip()
print(info)
68 changes: 61 additions & 7 deletions python/setup.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,62 @@
import sys
from pathlib import Path

from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext

version = '0.1.96'

from setuptools import setup
import pathlib
NAME = 'yamlscript'
PACKAGE_DIR = 'lib'
EXTENSIONS = dict(linux='so', darwin='dylib')
so = EXTENSIONS.get(sys.platform)

root = pathlib.Path(__file__).parent.resolve()
if not so:
raise RuntimeError(f"Unsupported platform: {sys.platform}. Should be one of {','.join(EXTENSIONS.keys())}.")

root = Path(__file__).parent.resolve()
filename = f"lib{NAME}.{so}.{version}"
path_lib = root / PACKAGE_DIR / NAME / filename
long_description = \
(root / '.long_description.md') \
.read_text(encoding='utf-8')

class LibYAMLScriptExtensionBuilder(build_ext):
"""

The shared library is pre-built, but we need to provide setuptools
with a dummy extension builder, so that it knows that the wheels
aren't just pure-Python and tags them with the correct
platform/architecture-specific naming and metadata.

"""

def build_extensions(self):
"""

Build nothing.

"""
pass


if path_lib.exists():
# If the shared library exists, only then add the relevant extension builder.
# Otherwise keep the package generic.
extension_config = dict(
ext_modules=[
Extension(name=NAME, sources=[])
],
cmdclass=dict(
build_ext=LibYAMLScriptExtensionBuilder,
),
package_data={NAME: [filename]},
)
else:
extension_config = dict()

setup(
name = 'yamlscript',
name=NAME,
version = version,
description = 'Program in YAML — Code is Data',
license = 'MIT',
Expand All @@ -19,10 +65,10 @@
author = 'Ingy döt Net',
author_email = '[email protected]',

packages = ['yamlscript'],
package_dir = {'': 'lib'},
packages=[NAME],
package_dir={'': PACKAGE_DIR},

python_requires = '>=3.6, <4',
python_requires='>=3.6, <4',
install_requires = [
'pyyaml',
],
Expand All @@ -45,4 +91,12 @@

long_description = long_description,
long_description_content_type = 'text/markdown',

entry_points=dict(
console_scripts=[
f'ys-py-show-info = {NAME}:show_info',
],
),

**extension_config,
)