Skip to content
This repository was archived by the owner on Aug 25, 2024. It is now read-only.

Commit cb02b31

Browse files
committed
util: testing: manifest: shim: docs: console examples: Show how to load correct wheel on the fly
Signed-off-by: John Andersen <[email protected]>
1 parent 0be7ea7 commit cb02b31

File tree

1 file changed

+60
-21
lines changed

1 file changed

+60
-21
lines changed

dffml/util/testing/manifest/shim.py

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -748,17 +748,44 @@ def shim(
748748
:test:
749749
:filepath: my_shim_setup.py
750750
751+
"""
752+
Ensure we can parse YAML manifests. Do this by downloading PyYAML to a
753+
cache directory and doing a direct import, or downloading to a tempdir
754+
every execution. If it's already installed, great. This should be a last
755+
resort.
756+
"""
757+
import re
758+
import sys
751759
import pathlib
752760
import tempfile
761+
import platform
753762
import zipimport
763+
import contextlib
754764
import urllib.request
755765
756766
import shim
757767
758-
# For the sake of the example assume you are unable to preinstall
759-
# anything into the environment the shim run in (common reason why we
760-
# use a shim).
761-
PYYAML_URL: str = "https://files.pythonhosted.org/packages/eb/5f/6e6fe6904e1a9c67bc2ca5629a69e7a5a0b17f079da838bab98a1e548b25/PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"
768+
# In the event that PyYAML is not installed this installs it locally
769+
# (relative to this file)
770+
PYYAML_URL: str = "https://pypi.org/simple/pyyaml/"
771+
CACHE: pathlib.Path = pathlib.Path(__file__).resolve().parent.joinpath(
772+
".cache", "wheels",
773+
)
774+
775+
776+
@contextlib.contextmanager
777+
def cache_dir():
778+
"""
779+
Try to cache locally if possible, create a directory to store wheels in
780+
relative to this file. If that fails, use a tempdir.
781+
"""
782+
try:
783+
CACHE.mkdir(parents=True, exist_ok=True)
784+
yield CACHE
785+
except:
786+
with tempfile.TemporaryDirectory() as tempdir:
787+
yield tempdir
788+
762789
763790
def setup_shim_func(parsers, next_phase_parsers, **kwargs):
764791
# Declare another parser
@@ -772,16 +799,36 @@ def setup_shim_func(parsers, next_phase_parsers, **kwargs):
772799
# Add the parser
773800
next_phase_parsers[(parser.format, parser.version, parser.name)] = parser
774801
775-
# Create a temporary directory to hold the pi
776-
with tempfile.TemporaryDirectory() as tempdir:
802+
# Download PyYAML and load the parser if not preloaded
803+
if "yaml" not in parsers:
804+
return
805+
806+
# Use ether the cache or a temporary directory to hold the package
807+
with cache_dir() as package_dir:
777808
# Path to wheel on disk
778-
wheel_path = pathlib.Path(tempdir, "package.whl")
779-
# Download the wheel
780-
with urllib.request.urlopen(PYYAML_URL) as response:
781-
wheel_path.write_bytes(response.read())
782-
# You'll need to change the wheel for this code to work
783-
if True:
784-
return
809+
wheel_path = pathlib.Path(package_dir, "package.whl")
810+
# Download if not cached
811+
if not wheel_path.exists():
812+
# Find the correct package
813+
with urllib.request.urlopen(PYYAML_URL) as response:
814+
links = re.findall(r"(https://.*.whl)", response.read().decode())
815+
# Search backwards because last links are the most recent package versions
816+
end_href = '" '
817+
links = [
818+
link[: link.index(end_href)]
819+
for link in links[::-1]
820+
if (
821+
end_href in link
822+
and f"cp{sys.version_info.major}{sys.version_info.minor}" in link
823+
and platform.machine() in link
824+
and {"darwin": "macos"}.get(sys.platform, sys.platform) in link
825+
)
826+
]
827+
# Grab the most recent applicable wheel link
828+
wheel_url = links[0]
829+
# Download the wheel
830+
with urllib.request.urlopen(wheel_url) as response:
831+
wheel_path.write_bytes(response.read())
785832
# Load the module from the downloaded wheel
786833
yaml = zipimport.zipimporter(str(wheel_path)).load_module("yaml")
787834
# Setup the parser for use by the shim
@@ -918,14 +965,6 @@ def make_parser():
918965
description=__doc__,
919966
)
920967

921-
# TODO Addition of remotely loadable PyPi zip packages? Perhaps it's easier
922-
# if we allow for the importing of a setup file with a setup function in it
923-
# that is called with the shim execution context (the arguments to shim()).
924-
# This is useful because often we find ourselves in a situation where the
925-
# reason we are using the shim is that we have no other dependencies
926-
# installed other than Python itself. Adding the ability to add more parsers
927-
# via the importing of another file which can then import or implement
928-
# parsers would be good.
929968
parser.add_argument(
930969
"-l", "--lockdown", action="store_true", default=False,
931970
)

0 commit comments

Comments
 (0)