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
19 changes: 15 additions & 4 deletions linkml_model/linkml_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,14 @@ def _build_path(source: Source, fmt: Format) -> str:
return filename


# Published schema/artifact files live under the ``linkml_model`` package directory
# on GitHub (raw + GitHub Pages), so GitHub URLs need this prefix even though
# ``LOCAL_PATH_FOR`` does not (its base already points inside the package).
PACKAGE_DIR = "linkml_model"


def _build_loc(base: str, source: Source, fmt: Format) -> str:
return f"{base}{_build_path(source, fmt)}".replace('blob/', '')
return f"{base}{PACKAGE_DIR}/{_build_path(source, fmt)}".replace('blob/', '')


def URL_FOR(source: Source, fmt: Format) -> str:
Expand All @@ -133,8 +139,13 @@ def LOCAL_PATH_FOR(source: Source, fmt: Format) -> str:
return os.path.join(LOCAL_BASE, _build_path(source, fmt))


def GITHUB_IO_PATH_FOR(source: Source, fmt: Format) -> str:
return _build_loc(GITHUB_IO_BASE, source, fmt)
def GITHUB_IO_PATH_FOR(source: Source, fmt: Format, version: str = "latest") -> str:
"""Return the GitHub Pages URL for source in format.

The docs site is versioned, so files live under ``<version>/linkml_model/``;
``version`` defaults to the ``latest`` alias.
"""
return f"{GITHUB_IO_BASE}{version}/{PACKAGE_DIR}/{_build_path(source, fmt)}"


def GITHUB_PATH_FOR(source: Source,
Expand All @@ -159,7 +170,7 @@ def tag_to_commit(tag: str) -> str:

# Return the absolute latest entry for branch
if release is ReleaseTag.LATEST or (release is ReleaseTag.CURRENT and branch != "main"):
return f"{GITHUB_BASE}{branch}/{_build_path(source, fmt)}"
return f"{GITHUB_BASE}{branch}/{PACKAGE_DIR}/{_build_path(source, fmt)}"

# Return the latest published version
elif release is ReleaseTag.CURRENT:
Expand Down
165 changes: 108 additions & 57 deletions tests/test_linkml_files.py
Original file line number Diff line number Diff line change
@@ -1,65 +1,116 @@
import os
import unittest
import re
from pathlib import Path

import pytest

import linkml_model.linkml_files as fileloc
from linkml_model.linkml_files import URL_FOR, Format, Source, LOCAL_PATH_FOR, GITHUB_IO_PATH_FOR, GITHUB_PATH_FOR, \
ReleaseTag
from linkml_model.linkml_files import (
URL_FOR,
Format,
Source,
LOCAL_PATH_FOR,
GITHUB_IO_PATH_FOR,
GITHUB_PATH_FOR,
ReleaseTag,
)
from tests import abspath
from pathlib import Path

root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "linkml_model"))

SKIP_GITHUB_API = False # True means don't do the github API tests


class LinkMLFilesTestCase(unittest.TestCase):
""" Test that linkml_model/linkml_files.py work """
def test_basic_rules(self):
self.assertEqual("https://w3id.org/linkml/annotations.yaml",
URL_FOR(Source.ANNOTATIONS, Format.YAML))
self.assertEqual("https://w3id.org/linkml/meta.model.context.jsonld",
URL_FOR(Source.META, Format.NATIVE_JSONLD))
self.assertEqual(os.path.join(root_path, "model/schema/meta.yaml"),
LOCAL_PATH_FOR(Source.META, Format.YAML))
print(LOCAL_PATH_FOR(Source.META, Format.YAML))
self.assertEqual(os.path.join(root_path, "jsonld/types.model.context.jsonld"),
LOCAL_PATH_FOR(Source.TYPES, Format.NATIVE_JSONLD))
self.assertEqual("https://linkml.github.io/linkml-model/model/schema/meta.yaml",
GITHUB_IO_PATH_FOR(Source.META, Format.YAML))
self.assertEqual("https://linkml.github.io/linkml-model/jsonld/types.model.context.jsonld",
GITHUB_IO_PATH_FOR(Source.TYPES, Format.NATIVE_JSONLD))
self.assertEqual("https://raw.githubusercontent.com/linkml/linkml-model/main/jsonld/meta.model.context.jsonld",
GITHUB_PATH_FOR(Source.META, Format.NATIVE_JSONLD, ReleaseTag.LATEST))
self.assertEqual("https://raw.githubusercontent.com/linkml/linkml-model/testing_branch/owl/mappings.owl.ttl",
GITHUB_PATH_FOR(Source.MAPPINGS, Format.OWL, branch="testing_branch"))

@unittest.skipIf(SKIP_GITHUB_API, "Github API tests skipped")
def test_github_specific_rules(self):
"""
Test accesses that require github API to access
This is separate because we can only do so many tests per hour w/o getting a 403
"""
self.assertEqual("https://raw.githubusercontent.com/linkml/linkml-model/f30637f5a585f3fc4b12fd3dbb3e7e95108d4b42/jsonld/meta.model.context.jsonld",
GITHUB_PATH_FOR(Source.META, Format.NATIVE_JSONLD, "v0.0.1"))
current_loc = re.sub(r'linkml-model/[0-9a-f]*/', 'linkml-model/SHA/', GITHUB_PATH_FOR(Source.TYPES, Format.YAML))
self.assertEqual("https://raw.githubusercontent.com/linkml/linkml-model/SHA/model/schema/types.yaml", current_loc)
# TODO: We may want to raise an error here?
self.assertEqual('https://raw.githubusercontent.com/linkml/linkml-model/missing_branch/owl/mappings.owl.ttl',
GITHUB_PATH_FOR(Source.MAPPINGS, Format.OWL, branch="missing_branch"))

with self.assertRaises(ValueError) as e:
GITHUB_PATH_FOR(Source.META, Format.RDF, "vv0.0.1")
self.assertEqual("Tag: vv0.0.1 not found!", str(e.exception))

def test_shorthand_paths(self):
self.assertEqual('meta', str(fileloc.meta))
self.assertEqual('meta.yaml', str(fileloc.meta.yaml))
self.assertEqual('meta.py', str(fileloc.meta.python))
self.assertEqual(Path(abspath('linkml_model/model/schema/meta.yaml')), Path(fileloc.meta.yaml.file))
self.assertEqual('https://linkml.github.io/linkml-model/model/schema/meta.yaml', str(fileloc.meta.yaml.github_loc()))
self.assertEqual('https://raw.githubusercontent.com/linkml/linkml-model/f30637f5a585f3fc4b12fd3dbb3e7e95108d4b42/model/schema/meta.yaml', str(fileloc.meta.yaml.github_loc('v0.0.1')))


if __name__ == '__main__':
unittest.main()
# The GitHub API tests resolve tags/releases to commits via the live GitHub API,
# which is rate-limited and flaky in CI, so they are opt-in.
# Set LINKML_TEST_GITHUB_API=1 to run them.
RUN_GITHUB_API = os.environ.get("LINKML_TEST_GITHUB_API", "").lower() in {"1", "true", "yes", "on"}

Comment thread
amc-corey-cox marked this conversation as resolved.

def test_url_for():
"""URL_FOR builds w3id.org URLs from the format extension."""
assert URL_FOR(Source.ANNOTATIONS, Format.YAML) == "https://w3id.org/linkml/annotations.yaml"
assert URL_FOR(Source.META, Format.NATIVE_JSONLD) == "https://w3id.org/linkml/meta.model.context.jsonld"


def test_local_path_for():
"""LOCAL_PATH_FOR points at the on-disk file inside the linkml_model package."""
assert LOCAL_PATH_FOR(Source.META, Format.YAML) == os.path.join(root_path, "model/schema/meta.yaml")
assert LOCAL_PATH_FOR(Source.TYPES, Format.NATIVE_JSONLD) == os.path.join(
root_path, "jsonld/types.model.context.jsonld"
)


def test_github_io_path_for():
"""GitHub Pages URLs are versioned and live under <version>/linkml_model/."""
assert (
GITHUB_IO_PATH_FOR(Source.META, Format.YAML)
== "https://linkml.github.io/linkml-model/latest/linkml_model/model/schema/meta.yaml"
)
assert (
GITHUB_IO_PATH_FOR(Source.TYPES, Format.NATIVE_JSONLD)
== "https://linkml.github.io/linkml-model/latest/linkml_model/jsonld/types.model.context.jsonld"
)
# the version segment is overridable
assert (
GITHUB_IO_PATH_FOR(Source.META, Format.YAML, version="v1.11.0")
== "https://linkml.github.io/linkml-model/v1.11.0/linkml_model/model/schema/meta.yaml"
)


def test_github_path_for_branch():
"""Branch / LATEST raw URLs are pure string formatting (no network)."""
assert (
GITHUB_PATH_FOR(Source.META, Format.NATIVE_JSONLD, ReleaseTag.LATEST)
== "https://raw.githubusercontent.com/linkml/linkml-model/main/linkml_model/jsonld/meta.model.context.jsonld"
)
assert (
GITHUB_PATH_FOR(Source.MAPPINGS, Format.OWL, branch="testing_branch")
== "https://raw.githubusercontent.com/linkml/linkml-model/testing_branch/linkml_model/owl/mappings.owl.ttl"
)
# TODO: a non-existent branch is not validated and yields a non-resolving URL
assert (
GITHUB_PATH_FOR(Source.MAPPINGS, Format.OWL, branch="missing_branch")
== "https://raw.githubusercontent.com/linkml/linkml-model/missing_branch/linkml_model/owl/mappings.owl.ttl"
)


def test_github_path_for_release_and_branch_conflict():
"""Specifying both a release and a non-main branch is an error (no network)."""
with pytest.raises(ValueError):
GITHUB_PATH_FOR(Source.META, Format.RDF, ReleaseTag.LATEST, branch="some_branch")


@pytest.mark.skipif(
not RUN_GITHUB_API,
reason="set LINKML_TEST_GITHUB_API=1 to run rate-limited GitHub API tests",
)
def test_github_specific_rules():
"""Tag / release resolution via the GitHub API.

Note: the builder applies the current ``linkml_model/`` layout uniformly to
all tags. Pre-restructure tags (e.g. v0.0.1) stored artifacts at the repo
root, so the URL generated for those very old tags uses the current layout
rather than their historical one and will not resolve.
"""
assert GITHUB_PATH_FOR(Source.META, Format.NATIVE_JSONLD, "v0.0.1") == (
"https://raw.githubusercontent.com/linkml/linkml-model/"
"f30637f5a585f3fc4b12fd3dbb3e7e95108d4b42/linkml_model/jsonld/meta.model.context.jsonld"
)
current_loc = re.sub(
r"linkml-model/[0-9a-f]{40}/", "linkml-model/SHA/", GITHUB_PATH_FOR(Source.TYPES, Format.YAML)
)
assert current_loc == (
"https://raw.githubusercontent.com/linkml/linkml-model/SHA/linkml_model/model/schema/types.yaml"
)
with pytest.raises(ValueError, match="Tag: vv0.0.1 not found!"):
GITHUB_PATH_FOR(Source.META, Format.RDF, "vv0.0.1")


def test_shorthand_paths():
"""The ModelFile shorthand accessors mirror the underlying functions."""
assert str(fileloc.meta) == "meta"
assert str(fileloc.meta.yaml) == "meta.yaml"
assert str(fileloc.meta.python) == "meta.py"
assert Path(fileloc.meta.yaml.file) == Path(abspath("linkml_model/model/schema/meta.yaml"))
assert (
str(fileloc.meta.yaml.github_loc())
== "https://linkml.github.io/linkml-model/latest/linkml_model/model/schema/meta.yaml"
)
Loading