Pure MoonBit toolkit for Python versions, metadata, indexes, locks and auditable candidate selection.
import {
"123123213weqw/moon_pyversion" @pyversion,
}///|
fn main {
let v = try! @pyversion.Version::parse("v01.002-rc3+ABC_007")
println(@pyversion.Version::to_string(v))
let spec = try! @pyversion.SpecifierSet::parse(">=1.0, !=1.4.*, <2.0")
let accepted = @pyversion.SpecifierSet::filter(
[try! @pyversion.Version::parse("1.5")],
spec,
)
println(accepted.length())
}pub(all) suberror MarkerError {
UndefinedEnvironmentName(String)
UndefinedComparison(String)
SetValuedOnLeft(String, String)
}impl Show for MarkerErrorpub(all) suberror VersionError {
InvalidVersion(String, Int)
InvalidSpecifier(String, Int)
InvalidName(String, Int)
InvalidFilename(String, Int)
InvalidRequirement(String, Int)
InvalidMarker(String, Int)
InvalidToml(String, Int)
InvalidLicense(String, Int)
InvalidMetadata(String, Int)
InvalidIndex(String, Int)
InvalidPylock(String, Int)
InvalidTag(String, Int)
} derive(Eq, Debug)impl Show for VersionErrorpub(all) struct AuditBundle {
reports : Array[PackageAudit]
issues : Array[AuditIssue]
} derive(Eq, Debug)pub(all) struct IndexFile {
filename : String
path : String
kind : IndexFileKind
name : String
version : Version
requires_python : String?
} derive(Eq, Debug)fn LocalIndex::scan(directory : String, lister? : (String) -> Array[String] raise VersionError) -> LocalIndex raise VersionErrorpub(all) struct MarkerClause {
lhs : MarkerOperand
op : MarkerOp
rhs : MarkerOperand
} derive(Eq, Debug)fn MarkerEnvironment::lookup(self : MarkerEnvironment, variable : MarkerVar) -> MarkerValue raise MarkerErrorfn MarkerEnvironment::set_names(self : MarkerEnvironment, key : String, value : Array[String]) -> Unitpub(all) struct Metadata {
metadata_version : String
name : String
version : Version
summary : String?
description : String?
description_content_type : String?
keywords : Array[String]
author : String?
author_email : String?
author_email_addresses : Array[(String, String)]
maintainer : String?
maintainer_email : String?
maintainer_email_addresses : Array[(String, String)]
license : String?
license_expression : String?
home_page : String?
download_url : String?
requires_python : String?
classifiers : Array[String]
requires_dist : Array[String]
requires_external : Array[String]
project_urls : Array[(String, String)]
provides_extra : Array[String]
provides_dist : Array[String]
obsoletes_dist : Array[String]
dynamic : Array[String]
platforms : Array[String]
supported_platforms : Array[String]
license_files : Array[String]
import_names : Array[String]
import_namespaces : Array[String]
requires : Array[String]
provides : Array[String]
obsoletes : Array[String]
raw : String
} derive(Eq, Debug)let metadata = Metadata::parse(
"Metadata-Version: 2.1\nName: demo\nVersion: 1.0\n\nHello.\n",
)
metadata.name // "demo"
metadata.version.to_string() // "1.0"
metadata.description // Some("Hello.\n")pub(all) struct PackageAudit {
project : String
requirement : String
applicable : Bool
metadata_name : String
metadata_version : String
index_name : String
index_files : Int
ignored_index_files : Int
yanked_files : Int
candidates : Array[String]
selected_file : String?
selected_version : String?
lock_versions : Array[String]
issues : Array[AuditIssue]
} derive(Eq, Debug)fn Pylock::accepts_environment(self : Pylock, environment : MarkerEnvironment) -> Bool raise MarkerErrorfn Pylock::applicable_packages(self : Pylock, environment : MarkerEnvironment) -> Array[PylockPackage] raise MarkerErrorfn Pylock::is_applicable(self : Pylock, name : String, environment : MarkerEnvironment) -> Bool raise MarkerErrorlet lock = Pylock::parse(
"lock-version = \"1.0\"\ncreated-by = \"demo\"\n\n[[packages]]\nname = \"attrs\"\nversion = \"25.1.0\"\n[[packages.wheels]]\nname = \"attrs-25.1.0-py3-none-any.whl\"\nhashes = { sha256 = \"c75a69e2\" }\n",
)
lock.files_for("attrs")[0].filename() // Some("attrs-25.1.0-py3-none-any.whl")pub(all) struct PylockFile {
name : String?
url : String?
path : String?
hashes : Array[(String, String)]
size : Int64?
upload_time : String?
subdirectory : String?
kind : PylockFileKind
} derive(Eq, Debug)pub(all) struct PylockPackage {
name : String
version : Version?
marker : String?
requires_python : String?
dependencies : Array[PylockDependency]
files : Array[PylockFile]
wheels : Array[PylockFile]
sdist : PylockFile?
archive : PylockFile?
vcs : PylockVcs?
directory : PylockDirectory?
index : String?
path : String?
} derive(Eq, Debug)fn PylockPackage::is_applicable(self : PylockPackage, environment : MarkerEnvironment) -> Bool raise MarkerErrorpub(all) struct Requirement {
name : String
extras : Array[String]
specifier : SpecifierSet
url : String?
marker_text : String?
raw : String
} derive(Debug)impl Show for Requirementlet r = try! Requirement::parse("Requests[Security]>=2.0,<3.0 ; python_version >= \"3.8\"")
r.name // "Requests"
r.extras // ["Security"]
r.specifier.to_string() // "<3.0,>=2.0"
r.marker_text // Some("python_version >= \"3.8\"")pub struct SimpleIndex {
name : String
api_version : String?
files : Array[SimpleIndexFile]
versions : Array[String]
} derive(Debug)pub(all) struct SimpleIndexFile {
filename : String
url : String
hashes : Array[(String, String)]
requires_python : String?
yanked : SimpleYanked
size : Int?
upload_time : String?
} derive(Eq, Debug)pub(all) struct Specifier {
op : SpecifierOp
raw_version : String
version : Version?
wildcard : Bool
} derive(Debug)test {
let spec = @moon_pyversion.Specifier::parse(">=1.4")
let hit = @moon_pyversion.Version::parse("1.5")
inspect(@moon_pyversion.Specifier::contains(spec, hit), content="true")
}impl Show for SpecifierSetfn SpecifierSet::filter(versions : Array[Version], spec : SpecifierSet, prereleases? : Bool?) -> Array[Version]test {
let spec = @moon_pyversion.SpecifierSet::parse(">=1.0, <2.0")
let candidates = [
@moon_pyversion.Version::parse("0.9"),
@moon_pyversion.Version::parse("1.5"),
]
inspect(
@moon_pyversion.SpecifierSet::filter(candidates, spec).length(),
content="1",
)
}let c = UpgradeCandidate::parse("1.2.3", Some(">=3.8"))
c.version.unwrap().to_string() // "1.2.3"pub(all) struct UpgradePlan {
shortlist : Array[UpgradeCandidate]
dropped : Array[(UpgradeCandidate, UpgradeRejection)]
} derive(Debug)test {
let v = @moon_pyversion.Version::parse("1.0rc1.post2+local")
inspect(@moon_pyversion.Version::base_version(v), content="1.0")
}test {
let v = @moon_pyversion.Version::parse("1.0rc1")
inspect(@moon_pyversion.Version::is_prerelease(v), content="true")
}fn audit_bundle(inputs : Array[AuditInput], pylock_toml : String, environment : MarkerEnvironment, python_text : String, tags : Array[String], allow_yanked? : Bool, require_lock_coverage? : Bool) -> AuditBundle raisefn audit_package(requirement_text : String, metadata_text : String, index_json : String, pylock_toml : String, environment : MarkerEnvironment, python_text : String, tags : Array[String], allow_yanked? : Bool) -> PackageAudit raisecanonicalize_license_expression("mit") // "MIT"
canonicalize_license_expression("mit and (apache-2.0 or bsd-2-clause)")
// "MIT AND (Apache-2.0 OR BSD-2-Clause)"canonicalize_license_file("LICENSE") // "LICENSE"
canonicalize_license_file("licenses/PSF-2.0.txt") // unchanged
canonicalize_license_file("./LICENSE") // raises NOT_POSIX_PATH
canonicalize_license_file("a/../b") // raises PARENT_DIRECTORYfn canonicalize_name(name : String) -> Stringtest {
inspect(
@moon_pyversion.canonicalize_name("Flask_Login"),
content="flask-login",
)
}fn canonicalize_version(version : String, strip_trailing_zero? : Bool) -> Stringcanonicalize_version("1.0.0") // "1"
canonicalize_version("1.4.0.0.0") // "1.4"
canonicalize_version("1.0.0.post0") // "1.post0"
canonicalize_version("1!2.0") // "1!2"
canonicalize_version("0.0") // "0"
canonicalize_version("nope") // "nope"
canonicalize_version("1.0.0", strip_trailing_zero=false) // "1.0.0"fn compatible_tags(python_version : Array[Int], interpreter : String?, platforms : Array[String]) -> Array[String] raise VersionErrorfn cpython_tags(python_version : Array[Int], abis : Array[String], platforms : Array[String]) -> Array[String] raise VersionErrorcpython_tags([3, 12], ["cp312"], ["linux_x86_64"])
// ["cp312-cp312-linux_x86_64", "cp312-abi3-linux_x86_64",
// "cp312-none-linux_x86_64", "cp311-abi3-linux_x86_64", ...]fn generic_tags(interpreter : String, abis : Array[String], platforms : Array[String]) -> Array[String] raise VersionErrorfn is_valid_license_expression(raw : String) -> Boollet s = parse_sdist_filename("flask-3.0.3.tar.gz")
s.name // "flask"
s.version.to_string() // "3.0.3"let w = parse_wheel_filename("numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.whl")
w.name // "numpy"
w.version.to_string() // "1.26.4"
w.build // None
w.tags // ["cp312-cp312-manylinux_2_17_x86_64"]fn upgrade_shortlist(current : Version, target : SpecifierSet?, prereleases : Bool?, python : Version?, candidates : Array[UpgradeCandidate]) -> UpgradePlanInstall
Download zipPure MoonBit toolkit for Python versions, metadata, indexes, locks and auditable candidate selection.