Skip to content

Commit 00e2949

Browse files
committed
backpropagating linkml_file changes
See: linkml/linkml#2540 Backpropagating changes from: linkml/linkml-runtime#320
1 parent 7d68f59 commit 00e2949

File tree

2 files changed

+260
-119
lines changed

2 files changed

+260
-119
lines changed

linkml_model/linkml_files.py

Lines changed: 107 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import os
1+
from pathlib import Path
22
from enum import Enum, auto
3-
from typing import Optional, Union
3+
from typing import Dict, Optional, Union, Tuple, NamedTuple
4+
from urllib.parse import urljoin
5+
from dataclasses import dataclass
46

57
import requests
68
from rdflib import Namespace
@@ -9,14 +11,12 @@
911
LINKML_NAMESPACE = Namespace(LINKML_URL_BASE)
1012
GITHUB_IO_BASE = "https://linkml.github.io/linkml-model/"
1113
GITHUB_BASE = "https://raw.githubusercontent.com/linkml/linkml-model/"
12-
LOCAL_BASE = os.path.abspath(os.path.dirname(__file__))
14+
LOCAL_BASE = Path(__file__).parent.resolve()
1315
GITHUB_API_BASE = "https://api.github.com/repos/linkml/linkml-model/"
1416
GITHUB_RELEASES = GITHUB_BASE + "releases"
1517
GITHUB_TAGS = GITHUB_BASE + "tags"
1618

1719

18-
19-
2020
class _AutoName(Enum):
2121
@staticmethod
2222
def _generate_next_value_(name, start, count, last_values):
@@ -32,42 +32,84 @@ class Source(_AutoName):
3232
EXTENSIONS = auto()
3333

3434

35-
class Format(Enum):
35+
class Format(_AutoName):
3636
""" LinkML package formats """
37-
GRAPHQL = "graphql"
38-
HTML = ""
39-
JSON = "json"
40-
JSONLD = "context.jsonld"
41-
JSON_SCHEMA = "schema.json"
42-
NATIVE_JSONLD = "model.context.jsonld"
43-
NATIVE_RDF = "model.ttl"
44-
NATIVE_SHEXC = "model.shex"
45-
NATIVE_SHEXJ = "model.shexj"
46-
OWL = "owl.ttl"
47-
PYTHON = "py"
48-
RDF = "ttl"
49-
SHEXC = "shex"
50-
SHEXJ = "shexj"
51-
YAML = "yaml"
52-
53-
54-
class _Path(Enum):
37+
EXCEL = auto()
38+
GRAPHQL = auto()
39+
JSON = auto()
40+
JSONLD = auto()
41+
JSON_SCHEMA = auto()
42+
NATIVE_JSONLD = auto()
43+
NATIVE_RDF = auto()
44+
NATIVE_SHEXC = auto()
45+
NATIVE_SHEXJ = auto()
46+
OWL = auto()
47+
PREFIXMAP = auto()
48+
PROTOBUF = auto()
49+
PYTHON = auto()
50+
RDF = auto()
51+
SHACL = auto()
52+
SHEXC = auto()
53+
SHEXJ = auto()
54+
SQLDDL = auto()
55+
SQLSCHEMA = auto()
56+
YAML = auto()
57+
58+
@dataclass
59+
class FormatPath:
60+
path: str
61+
extension: str
62+
63+
def model_path(self, model:str) -> Path:
64+
return (Path(self.path) / model).with_suffix(self.extension)
65+
66+
class _Path:
5567
""" LinkML Relative paths"""
56-
GRAPHQL = "graphql"
57-
HTML = "docs"
58-
JSON = "json"
59-
JSONLD = "jsonld"
60-
JSON_SCHEMA = "jsonschema"
61-
NATIVE_JSONLD = "jsonld"
62-
NATIVE_RDF = "ttl"
63-
NATIVE_SHEXC = "shex"
64-
NATIVE_SHEXJ = "shex"
65-
OWL = "owl"
66-
PYTHON = "linkml_model"
67-
RDF = "rdf"
68-
SHEXC = "shex"
69-
SHEXJ = "shex"
70-
YAML = "model/schema"
68+
EXCEL = FormatPath("excel","xlsx" )
69+
GRAPHQL = FormatPath("graphql","graphql" )
70+
JSON = FormatPath("json","json" )
71+
JSONLD = FormatPath("jsonld","context.jsonld" )
72+
JSON_SCHEMA = FormatPath("jsonschema", "schema.json" )
73+
NATIVE_JSONLD = FormatPath("jsonld", "context.jsonld" )
74+
NATIVE_RDF = FormatPath("rdf","ttl" )
75+
NATIVE_SHEXC = FormatPath("shex","shex" )
76+
NATIVE_SHEXJ = FormatPath("shex","shexj" )
77+
OWL = FormatPath("owl","owl.ttl" )
78+
PREFIXMAP = FormatPath('prefixmap','yaml' )
79+
PROTOBUF = FormatPath("protobuf","proto" )
80+
PYTHON = FormatPath("","py" )
81+
RDF = FormatPath("rdf","ttl" )
82+
SHACL = FormatPath("shacl","shacl.ttl" )
83+
SHEXC = FormatPath("shex","shex" )
84+
SHEXJ = FormatPath("shex","shexj" )
85+
SQLDDL = FormatPath("sqlddl","sql" )
86+
SQLSCHEMA = FormatPath("sqlschema","sql" )
87+
YAML = FormatPath(str(Path("model") / "schema"),"yaml" )
88+
89+
@classmethod
90+
def items(cls) -> Dict[str, FormatPath]:
91+
return {k:v for k,v in cls.__dict__.items() if not k.startswith('_')}
92+
93+
@classmethod
94+
def get(cls, item:Union[str,Format]) -> FormatPath:
95+
if isinstance(item, Format):
96+
item = item.name.upper()
97+
return getattr(cls, item)
98+
99+
def __class_getitem__(cls, item:str) -> FormatPath:
100+
return getattr(cls, item)
101+
102+
103+
META_ONLY = (
104+
Format.EXCEL,
105+
Format.GRAPHQL,
106+
Format.OWL,
107+
Format.PREFIXMAP,
108+
Format.PROTOBUF,
109+
Format.SHACL,
110+
Format.SQLDDL,
111+
Format.SQLSCHEMA
112+
)
71113

72114

73115
class ReleaseTag(_AutoName):
@@ -78,26 +120,40 @@ class ReleaseTag(_AutoName):
78120
CURRENT = auto()
79121

80122

81-
def _build_path(source: Source, fmt: Format) -> str:
82-
""" Create the relative path for source and fmt """
83-
return f"{_Path[fmt.name].value}/{source.value}.{fmt.value}"
123+
class PathParts(NamedTuple):
124+
format: str
125+
file: str
126+
127+
128+
def _build_path(source: Source, fmt: Format) -> PathParts:
129+
"""
130+
Create the parts for a relative path for source and fmt.
131+
Combined elsewhere into a complete path, since OS paths and URLs differ.
132+
"""
133+
fmt_path: FormatPath = _Path.get(fmt.name)
134+
return PathParts(fmt_path.path, f"{source.value}.{fmt_path.extension}")
84135

85136

86137
def _build_loc(base: str, source: Source, fmt: Format) -> str:
87-
return f"{base}{_build_path(source, fmt)}".replace('blob/', '')
138+
"""A github location"""
139+
# urls are always forward slash separated, so hardcoding is appropriate here
140+
path = '/'.join(_build_path(source, fmt))
141+
return urljoin(base, path).replace('blob/', '')
88142

89143

90144
def URL_FOR(source: Source, fmt: Format) -> str:
91145
""" Return the URL to retrieve source in format """
92-
return f"{LINKML_URL_BASE}{source.value}.{fmt.value}"
146+
fmt_path: FormatPath = _Path.get(fmt.name)
147+
return f"{LINKML_URL_BASE}{source.value}.{fmt_path.extension}"
93148

94149

95150
def LOCAL_PATH_FOR(source: Source, fmt: Format) -> str:
96-
return os.path.join(LOCAL_BASE, _build_path(source, fmt))
151+
return str(LOCAL_BASE.joinpath(*_build_path(source, fmt)))
97152

98153

99-
def GITHUB_IO_PATH_FOR(source: Source, fmt: Format) -> str:
100-
return _build_loc(GITHUB_IO_BASE, source, fmt)
154+
def GITHUB_IO_PATH_FOR(source: Source, fmt: Format, version="latest") -> str:
155+
path = '/'.join([version, 'linkml_model', *_build_path(source, fmt)])
156+
return urljoin(GITHUB_IO_BASE, path)
101157

102158

103159
def GITHUB_PATH_FOR(source: Source,
@@ -122,7 +178,8 @@ def tag_to_commit(tag: str) -> str:
122178

123179
# Return the absolute latest entry for branch
124180
if release is ReleaseTag.LATEST or (release is ReleaseTag.CURRENT and branch != "main"):
125-
return f"{GITHUB_BASE}{branch}/{_build_path(source, fmt)}"
181+
path = '/'.join([branch, 'linkml_model', *_build_path(source, fmt)])
182+
return urljoin(GITHUB_BASE, path)
126183

127184
# Return the latest published version
128185
elif release is ReleaseTag.CURRENT:
@@ -139,9 +196,10 @@ class ModelLoc:
139196
def __init__(self, model: Source, fmt: Format) -> str:
140197
self._model = model
141198
self._format = fmt
199+
self._fmt_path = _Path.get(fmt.name)
142200

143201
def __str__(self):
144-
return f"{self._model.value}.{self._format.value}"
202+
return f"{self._model.value}.{self._fmt_path.extension}"
145203

146204
def __repr__(self):
147205
return str(self)
@@ -171,18 +229,10 @@ def __str__(self):
171229
def __repr__(self):
172230
return str(self)
173231

174-
@property
175-
def yaml(self) -> ModelLoc:
176-
return ModelFile.ModelLoc(self._model, Format.YAML)
177-
178232
@property
179233
def graphql(self) -> ModelLoc:
180234
return ModelFile.ModelLoc(self._model, Format.GRAPHQL)
181235

182-
@property
183-
def html(self) -> ModelLoc:
184-
return ModelFile.ModelLoc(self._model, Format.HTML)
185-
186236
@property
187237
def json(self) -> ModelLoc:
188238
return ModelFile.ModelLoc(self._model, Format.JSON)

0 commit comments

Comments
 (0)