PK! `c<<cnab/__init__.pyfrom dataclasses import dataclass, field from typing import Optional, Any, List, Union, Dict, TypeVar, Callable, Type, cast T = TypeVar("T") def from_bool(x: Any) -> bool: assert isinstance(x, bool) return x def from_none(x: Any) -> Any: assert x is None return x def from_union(fs, x): for f in fs: try: return f(x) except: pass assert False def from_str(x: Any) -> str: assert isinstance(x, str) return x def from_list(f: Callable[[Any], T], x: Any) -> List[T]: assert isinstance(x, list) return [f(y) for y in x] def from_int(x: Any) -> int: assert isinstance(x, int) and not isinstance(x, bool) return x def to_class(c: Type[T], x: Any) -> dict: assert isinstance(x, c) return cast(Any, x).to_dict() def from_dict(f: Callable[[Any], T], x: Any) -> Dict[str, T]: assert isinstance(x, dict) return {k: f(v) for (k, v) in x.items()} def clean(result: Dict) -> dict: return {k: v for k, v in result.items() if v} @dataclass class Action: modifies: Optional[bool] = None @staticmethod def from_dict(obj: Any) -> "Action": assert isinstance(obj, dict) modifies = from_union([from_bool, from_none], obj.get("modifies")) return Action(modifies) def to_dict(self) -> dict: result: dict = {} result["modifies"] = from_union([from_bool, from_none], self.modifies) return clean(result) @dataclass class Credential: description: Optional[str] = None env: Optional[str] = None path: Optional[str] = None @staticmethod def from_dict(obj: Any) -> "Credential": assert isinstance(obj, dict) description = from_union([from_str, from_none], obj.get("description")) env = from_union([from_str, from_none], obj.get("env")) path = from_union([from_str, from_none], obj.get("path")) return Credential(description, env, path) def to_dict(self) -> dict: result: dict = {} result["description"] = from_union([from_str, from_none], self.description) result["env"] = from_union([from_str, from_none], self.env) result["path"] = from_union([from_str, from_none], self.path) return clean(result) @dataclass class ImagePlatform: architecture: Optional[str] = None os: Optional[str] = None @staticmethod def from_dict(obj: Any) -> "ImagePlatform": assert isinstance(obj, dict) architecture = from_union([from_str, from_none], obj.get("architecture")) os = from_union([from_str, from_none], obj.get("os")) return ImagePlatform(architecture, os) def to_dict(self) -> dict: result: dict = {} result["architecture"] = from_union([from_str, from_none], self.architecture) result["os"] = from_union([from_str, from_none], self.os) return clean(result) @dataclass class Ref: field: Optional[str] = None media_type: Optional[str] = None path: Optional[str] = None @staticmethod def from_dict(obj: Any) -> "Ref": assert isinstance(obj, dict) field = from_union([from_str, from_none], obj.get("field")) media_type = from_union([from_str, from_none], obj.get("mediaType")) path = from_union([from_str, from_none], obj.get("path")) return Ref(field, media_type, path) def to_dict(self) -> dict: result: dict = {} result["field"] = from_union([from_str, from_none], self.field) result["mediaType"] = from_union([from_str, from_none], self.media_type) result["path"] = from_union([from_str, from_none], self.path) return clean(result) @dataclass class Image: image: str description: Optional[str] = None digest: Optional[str] = None image_type: Optional[str] = None media_type: Optional[str] = None platform: Optional[ImagePlatform] = None refs: List[Ref] = field(default_factory=list) size: Optional[int] = None @staticmethod def from_dict(obj: Any) -> "Image": assert isinstance(obj, dict) description = from_union([from_str, from_none], obj.get("description")) digest = from_union([from_str, from_none], obj.get("digest")) image = from_str(obj.get("image")) image_type = from_union([from_str, from_none], obj.get("imageType")) media_type = from_union([from_str, from_none], obj.get("mediaType")) platform = from_union([ImagePlatform.from_dict, from_none], obj.get("platform")) refs = from_union( [lambda x: from_list(Ref.from_dict, x), from_none], obj.get("refs") ) size = from_union([from_int, from_none], obj.get("size")) return Image( description, digest, image, image_type, media_type, platform, refs, size ) def to_dict(self) -> dict: result: dict = {} result["description"] = from_union([from_str, from_none], self.description) result["digest"] = from_union([from_str, from_none], self.digest) result["image"] = from_str(self.image) result["imageType"] = from_union([from_str, from_none], self.image_type) result["mediaType"] = from_union([from_str, from_none], self.media_type) result["platform"] = from_union( [lambda x: to_class(ImagePlatform, x), from_none], self.platform ) result["refs"] = from_list(lambda x: to_class(Ref, x), self.refs) result["size"] = from_union([from_int, from_none], self.size) return clean(result) @dataclass class InvocationImagePlatform: architecture: Optional[str] = None os: Optional[str] = None @staticmethod def from_dict(obj: Any) -> "InvocationImagePlatform": assert isinstance(obj, dict) architecture = from_union([from_str, from_none], obj.get("architecture")) os = from_union([from_str, from_none], obj.get("os")) return InvocationImagePlatform(architecture, os) def to_dict(self) -> dict: result: dict = {} result["architecture"] = from_union([from_str, from_none], self.architecture) result["os"] = from_union([from_str, from_none], self.os) return clean(result) @dataclass class InvocationImage: image: str digest: Optional[str] = None image_type: Optional[str] = None media_type: Optional[str] = None platform: Optional[InvocationImagePlatform] = None size: Optional[str] = None @staticmethod def from_dict(obj: Any) -> "InvocationImage": assert isinstance(obj, dict) digest = from_union([from_str, from_none], obj.get("digest")) image = from_str(obj.get("image")) image_type = from_union([from_str, from_none], obj.get("imageType")) media_type = from_union([from_str, from_none], obj.get("mediaType")) platform = from_union( [InvocationImagePlatform.from_dict, from_none], obj.get("platform") ) size = from_union([from_str, from_none], obj.get("size")) return InvocationImage(digest, image, image_type, media_type, platform, size) def to_dict(self) -> dict: result: dict = {} result["digest"] = from_union([from_str, from_none], self.digest) result["image"] = from_str(self.image) result["imageType"] = from_union([from_str, from_none], self.image_type) result["mediaType"] = from_union([from_str, from_none], self.media_type) result["platform"] = from_union( [lambda x: to_class(InvocationImagePlatform, x), from_none], self.platform ) result["size"] = from_union([from_str, from_none], self.size) return clean(result) @dataclass class Maintainer: email: Optional[str] = None name: Optional[str] = None url: Optional[str] = None @staticmethod def from_dict(obj: Any) -> "Maintainer": assert isinstance(obj, dict) email = from_union([from_str, from_none], obj.get("email")) name = from_union([from_str, from_none], obj.get("name")) url = from_union([from_str, from_none], obj.get("url")) return Maintainer(email, name, url) def to_dict(self) -> dict: result: dict = {} result["email"] = from_union([from_str, from_none], self.email) result["name"] = from_union([from_str, from_none], self.name) result["url"] = from_union([from_str, from_none], self.url) return clean(result) @dataclass class Destination: description: Optional[str] = None env: Optional[str] = None path: Optional[str] = None @staticmethod def from_dict(obj: Any) -> "Destination": assert isinstance(obj, dict) description = from_union([from_str, from_none], obj.get("description")) env = from_union([from_str, from_none], obj.get("env")) path = from_union([from_str, from_none], obj.get("path")) return Destination(description, env, path) def to_dict(self) -> dict: result: dict = {} result["description"] = from_union([from_str, from_none], self.description) result["env"] = from_union([from_str, from_none], self.env) result["path"] = from_union([from_str, from_none], self.path) return clean(result) @dataclass class Metadata: description: Optional[str] = None @staticmethod def from_dict(obj: Any) -> "Metadata": assert isinstance(obj, dict) description = from_union([from_str, from_none], obj.get("description")) return Metadata(description) def to_dict(self) -> dict: result: dict = {} result["description"] = from_union([from_str, from_none], self.description) return clean(result) @dataclass class Parameter: type: str default_value: Union[bool, int, None, str] = None allowed_values: Optional[List[Any]] = field(default_factory=list) destination: Optional[Destination] = None max_length: Optional[int] = None max_value: Optional[int] = None metadata: Optional[Metadata] = None min_length: Optional[int] = None min_value: Optional[int] = None required: Optional[bool] = None @staticmethod def from_dict(obj: Any) -> "Parameter": assert isinstance(obj, dict) allowed_values = from_union( [lambda x: from_list(lambda x: x, x), from_none], obj.get("allowedValues") ) default_value = from_union( [from_int, from_bool, from_none, from_str], obj.get("defaultValue") ) destination = from_union( [Destination.from_dict, from_none], obj.get("destination") ) max_length = from_union([from_int, from_none], obj.get("maxLength")) max_value = from_union([from_int, from_none], obj.get("maxValue")) metadata = from_union([Metadata.from_dict, from_none], obj.get("metadata")) min_length = from_union([from_int, from_none], obj.get("minLength")) min_value = from_union([from_int, from_none], obj.get("minValue")) required = from_union([from_bool, from_none], obj.get("required")) type = from_str(obj.get("type")) return Parameter( type, default_value, allowed_values, destination, max_length, max_value, metadata, min_length, min_value, required, ) def to_dict(self) -> dict: result: dict = {} result["allowedValues"] = from_list(lambda x: x, self.allowed_values) result["destination"] = from_union( [lambda x: to_class(Destination, x), from_none], self.destination ) result["maxLength"] = from_union([from_int, from_none], self.max_length) result["maxValue"] = from_union([from_int, from_none], self.max_value) result["metadata"] = from_union( [lambda x: to_class(Metadata, x), from_none], self.metadata ) result["minLength"] = from_union([from_int, from_none], self.min_length) result["minValue"] = from_union([from_int, from_none], self.min_value) result["required"] = from_union([from_bool, from_none], self.required) result["type"] = from_str(self.type) return clean(result) @dataclass class Bundle: name: str version: str invocation_images: List[InvocationImage] schema_version: Optional[str] = "v1" actions: Dict[str, Action] = field(default_factory=dict) credentials: Dict[str, Credential] = field(default_factory=dict) description: Optional[str] = None images: List[Image] = field(default_factory=list) keywords: List[str] = field(default_factory=list) maintainers: List[Maintainer] = field(default_factory=list) parameters: Dict[str, Parameter] = field(default_factory=dict) @staticmethod def from_dict(obj: Any) -> "Bundle": assert isinstance(obj, dict) actions = from_union( [lambda x: from_dict(Action.from_dict, x), from_none], obj.get("actions") ) credentials = from_union( [lambda x: from_dict(Credential.from_dict, x), from_none], obj.get("credentials"), ) description = from_union([from_str, from_none], obj.get("description")) images = from_union( [lambda x: from_list(Image.from_dict, x), from_none], obj.get("images") ) invocation_images = from_list( InvocationImage.from_dict, obj.get("invocationImages") ) keywords = from_union( [lambda x: from_list(from_str, x), from_none], obj.get("keywords") ) maintainers = from_union( [lambda x: from_list(Maintainer.from_dict, x), from_none], obj.get("maintainers"), ) name = from_str(obj.get("name")) parameters = from_union( [lambda x: from_dict(Parameter.from_dict, x), from_none], obj.get("parameters"), ) schema_version = from_union([from_str, from_none], obj.get("schemaVersion")) version = from_str(obj.get("version")) return Bundle( name, version, invocation_images, schema_version, actions, credentials, description, images, keywords, maintainers, parameters, ) def to_dict(self) -> dict: result: dict = {} result["actions"] = from_dict(lambda x: to_class(Action, x), self.actions) result["credentials"] = from_dict( lambda x: to_class(Credential, x), self.credentials ) result["description"] = from_union([from_str, from_none], self.description) result["images"] = from_list(lambda x: to_class(Image, x), self.images) result["invocationImages"] = from_list( lambda x: to_class(InvocationImage, x), self.invocation_images ) result["keywords"] = from_list(from_str, self.keywords) result["maintainers"] = from_list( lambda x: to_class(Maintainer, x), self.maintainers ) result["name"] = from_str(self.name) result["parameters"] = from_dict( lambda x: to_class(Parameter, x), self.parameters ) result["schemaVersion"] = from_str(self.schema_version) result["version"] = from_str(self.version) return clean(result) def bundle_from_dict(s: Any) -> Bundle: return Bundle.from_dict(s) def bundle_to_dict(x: Bundle) -> Any: return to_class(Bundle, x) PK!Lطcnab/test_cnab.pyimport json from cnab import Bundle, InvocationImage def test_create_bundle(): bundle = Bundle( name="sample", version="0.1.0", invocation_images=[ InvocationImage(image_type="docker", image="garethr/helloworld:0.1.0") ], ) assert bundle.to_dict() def test_read_bundle(): with open("bundle.json") as f: data = json.load(f) assert Bundle.from_dict(data) PK!<%[[cnab-0.1.1.dist-info/LICENSE pycnab Copyright (C) 2018 Gareth Rushgrove Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. PK!HnHTUcnab-0.1.1.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HzsRcnab-0.1.1.dist-info/METADATAUێ6}W 彤 E nuEE[J;#{hby83gP(KoAIv,9(+ qg?ʎd6`a Lƶfa\mw-kXZ;6z䆊U1OJf^OݾCra\NJON#Avz~" VHS Hʹ6:K5^I—/k*uVhCg-I|D*Gx6{͂b J:P(C IЅ}bKPHnq^?VtQr#w")!)i/sEl՞>kib wtlN>;A `Y37/MZugIAȦHlPվa6ZU ôCZC4 '?dYoԽ} RS~6. {z#&_Isg^w6?F-}~cnn$. M).^ 4FZ鿨?^#y]PK!Hn>(cnab-0.1.1.dist-info/RECORDm̻r@@oQBd7a!y)q&s[Uu><3}($Հ'Z!Qj#p%BKLsLP]~PWfN-w\l `V#j(OaScDb%16f15Y;k,`XI|稂FHel2'<7ƛx z!Vj!9X"u)I(9`cmKU(Yi9@mPPQ3窇5[3PK! `c<<cnab/__init__.pyPK!Lط =cnab/test_cnab.pyPK!<%[[>cnab-0.1.1.dist-info/LICENSEPK!HnHTU~Acnab-0.1.1.dist-info/WHEELPK!HzsR Bcnab-0.1.1.dist-info/METADATAPK!Hn>(\Fcnab-0.1.1.dist-info/RECORDPKG