1
1
from __future__ import annotations
2
2
3
+ import json
3
4
import logging
4
5
import os
6
+ import platform
7
+ import tarfile
5
8
import urllib .request
6
9
from collections .abc import Sequence
7
10
from dataclasses import dataclass , field
10
13
11
14
from .constants import (
12
15
FILENAME_METADATA_JSON ,
13
- MIME_APPLICATION_CONFIG ,
16
+ MIME_APPLICATION_MLMETADATA ,
14
17
MIME_APPLICATION_MLMODEL ,
18
+ MIME_BLOB ,
19
+ MIME_MANIFEST_CONFIG ,
15
20
)
16
21
from .listener import Event , Listener , PushEvent
17
22
from .model_metadata import ModelMetadata
20
25
logger = logging .getLogger (__name__ )
21
26
22
27
28
+ def get_arch () -> str :
29
+ mac = platform .machine ()
30
+ if mac == "x86_64" :
31
+ return "amd64"
32
+ if mac == "arm64" :
33
+ return "arm64"
34
+ if mac == "aarch64" :
35
+ return "arm64"
36
+ msg = f"Unsupported architecture: { platform .machine ()} "
37
+ raise NotImplementedError (msg )
38
+
39
+
23
40
def download_file (uri : str ):
24
41
file_name = os .path .basename (uri )
25
42
urllib .request .urlretrieve (uri , file_name )
@@ -41,6 +58,7 @@ def push(
41
58
self ,
42
59
target : str ,
43
60
path : Path | str ,
61
+ as_artifact : bool = False ,
44
62
** kwargs ,
45
63
):
46
64
owns_meta = True
@@ -52,8 +70,7 @@ def push(
52
70
owns_meta = False
53
71
logger .warning ("Reusing intermediate metadata files." )
54
72
logger .debug (f"{ meta_path } " )
55
- with open (meta_path , "r" ) as f :
56
- model_metadata = ModelMetadata .from_json (f .read ())
73
+ model_metadata = ModelMetadata .from_dict (json .loads (meta_path .read_bytes ()))
57
74
elif meta_path .exists ():
58
75
err = dedent (f"""
59
76
OMLMD intermediate metadata files found at '{ meta_path } '.
@@ -65,13 +82,51 @@ def push(
65
82
raise RuntimeError (err )
66
83
else :
67
84
model_metadata = ModelMetadata .from_dict (kwargs )
68
- meta_path .write_text (model_metadata .to_json ())
85
+ meta_path .write_text (json .dumps (model_metadata .to_dict ()))
86
+
87
+ owns_model_tar = False
88
+ owns_md_tar = False
89
+ manifest_path = path .parent / "manifest.json"
90
+ model_tar = None
91
+ meta_tar = None
92
+ if not as_artifact :
93
+ manifest_path .write_text (
94
+ json .dumps (
95
+ {
96
+ "architecture" : get_arch (),
97
+ "os" : "linux" ,
98
+ }
99
+ )
100
+ )
101
+ config = f"{ manifest_path } :{ MIME_MANIFEST_CONFIG } "
102
+ model_tar = path .parent / f"{ path .stem } .tar"
103
+ meta_tar = path .parent / f"{ meta_path .stem } .tar"
104
+ if not model_tar .exists ():
105
+ owns_model_tar = True
106
+ with tarfile .open (model_tar , "w" ) as tf :
107
+ tf .add (path , arcname = path .name )
108
+ if not meta_tar .exists ():
109
+ owns_md_tar = True
110
+ with tarfile .open (meta_tar , "w:gz" ) as tf :
111
+ tf .add (meta_path , arcname = meta_path .name )
112
+ files = [
113
+ f"{ model_tar } :{ MIME_BLOB } " ,
114
+ f"{ meta_tar } :{ MIME_BLOB } +gzip" ,
115
+ ]
116
+ else :
117
+ manifest_path .write_text (
118
+ json .dumps (
119
+ {
120
+ "artifactType" : MIME_APPLICATION_MLMODEL ,
121
+ }
122
+ )
123
+ )
124
+ config = f"{ manifest_path } :{ MIME_APPLICATION_MLMODEL } "
125
+ files = [
126
+ f"{ path } :{ MIME_APPLICATION_MLMODEL } " ,
127
+ f"{ meta_path } :{ MIME_APPLICATION_MLMETADATA } " ,
128
+ ]
69
129
70
- config = f"{ meta_path } :{ MIME_APPLICATION_CONFIG } "
71
- files = [
72
- f"{ path } :{ MIME_APPLICATION_MLMODEL } " ,
73
- config ,
74
- ]
75
130
try :
76
131
# print(target, files, model_metadata.to_annotations_dict())
77
132
result = self ._registry .push (
@@ -88,6 +143,12 @@ def push(
88
143
finally :
89
144
if owns_meta :
90
145
meta_path .unlink ()
146
+ if owns_model_tar :
147
+ assert isinstance (model_tar , Path )
148
+ model_tar .unlink ()
149
+ if owns_md_tar :
150
+ assert isinstance (meta_tar , Path )
151
+ meta_tar .unlink ()
91
152
92
153
def pull (
93
154
self , target : str , outdir : Path | str , media_types : Sequence [str ] | None = None
0 commit comments