1
0
mirror of https://github.com/containers/ramalama.git synced 2026-02-05 06:46:39 +01:00

updated build to remove setup.py dependency to fix cli entrypoint

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

removed uv.lock

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

reverts uv-install.sh, bin/ramalama, and flat cli hierarchy

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

packit version extraction from pyproject.toml

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

pyproject.toml references license file

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

fixed completion directory location

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

fixed format and check-format. There is no longer a root .py file to check

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

newline at end of install-uv.sh

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

remove *.py from make lint flake8 command

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

added import for ModelStoreImport to main

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

attempt to consolidate main functions

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

lint

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

Make bin/ramalama executable

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>

typo

Signed-off-by: Ian Eaves <ian.k.eaves@gmail.com>
This commit is contained in:
Ian Eaves
2025-05-04 16:40:07 -05:00
parent 7cc1052e0c
commit 785c66184b
19 changed files with 125 additions and 192 deletions

View File

@@ -6,8 +6,8 @@
set -exo pipefail
# Get Version from HEAD
VERSION=$(awk -F'[""]' '/version=/ {print $(NF-1)}' setup.py)
# Extract version from pyproject.toml instead of setup.py
VERSION=$(awk -F'[""]' ' /^\s*version\s*/ {print $(NF-1)}' pyproject.toml )
SPEC_FILE=rpm/python-ramalama.spec

7
MANIFEST.in Normal file
View File

@@ -0,0 +1,7 @@
include README.md LICENSE
include shortnames/shortnames.conf
include docs/*.1
include docs/*.5
include docs/*.7
recursive-include completions *
recursive-include libexec *

View File

@@ -126,18 +126,18 @@ ifneq (,$(wildcard /usr/bin/python3))
endif
! grep -ri "#\!/usr/bin/python3" .
flake8 *.py */*.py */*/*.py libexec/* bin/*
flake8 */*.py */*/*.py libexec/* bin/*
shellcheck *.sh */*.sh */*/*.sh
.PHONY: check-format
check-format:
black --check --diff *.py */*.py */*/*.py libexec/* bin/*
isort --check --diff *.py */*.py */*/*.py libexec/* bin/*
black --check --diff */*.py */*/*.py libexec/* bin/*
isort --check --diff */*.py */*/*.py libexec/* bin/*
.PHONY: format
format:
black *.py */*.py */*/*.py libexec/* bin/*
isort *.py */*.py */*/*.py libexec/* bin/*
black */*.py */*/*.py libexec/* bin/*
isort */*.py */*/*.py libexec/* bin/*
.PHONY: codespell
codespell:

View File

@@ -1,11 +1,8 @@
#!/usr/bin/env python3
import errno
import glob
import os
import subprocess
import sys
import urllib
def add_pipx_venvs_bin_to_path():
@@ -39,7 +36,7 @@ def add_site_packages_to_syspath(base_path):
sys.path.insert(0, path)
def main(args):
def main():
sharedirs = ["/opt/homebrew/share/ramalama", "/usr/local/share/ramalama", "/usr/share/ramalama"]
syspath = next((d for d in sharedirs if os.path.exists(d + "/ramalama/cli.py")), None)
if syspath:
@@ -55,54 +52,8 @@ def main(args):
print(f"ramalama module not found in sys.path: {sys.path}", file=sys.stderr)
raise
parser, args = ramalama.init_cli()
# if autocomplete doesn't exist, just do nothing, don't break
try:
import argcomplete
argcomplete.autocomplete(parser)
except Exception:
None
def eprint(e, exit_code):
ramalama.perror("Error: " + str(e).strip("'\""))
sys.exit(exit_code)
try:
from ramalama.migrate import ModelStoreImport
ModelStoreImport(args.store).import_all()
except Exception as ex:
print(f"Failed to import models to new store: {ex}")
# Process CLI
try:
args.func(args)
except urllib.error.HTTPError as e:
eprint(f"pulling {e.geturl()} failed: {e} ", errno.EINVAL)
except ramalama.HelpException:
parser.print_help()
except AttributeError as e:
parser.print_usage()
print("ramalama: requires a subcommand")
if args.debug:
raise e
except IndexError as e:
eprint(e, errno.EINVAL)
except KeyError as e:
eprint(e, 1)
except NotImplementedError as e:
eprint(e, errno.ENOTSUP)
except subprocess.CalledProcessError as e:
eprint(e, e.returncode)
except KeyboardInterrupt:
sys.exit(0)
except ValueError as e:
eprint(e, errno.EINVAL)
except IOError as e:
eprint(e, errno.EIO)
ramalama.cli.main()
if __name__ == "__main__":
main(sys.argv[1:])
main()

View File

@@ -1,18 +1,28 @@
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"
[project]
name = "ramalama"
version = "0.8.2"
description = "RamaLama is a command line tool for working with AI LLM models."
readme = "README.md"
requires-python = ">=3.8"
license = { file = "LICENSE" }
keywords = ["ramalama", "llama", "AI"]
dependencies = [
"argcomplete",
"argcomplete"
]
requires-python = ">= 3.8"
maintainers = [
{ name="Dan Walsh", email = "dwalsh@redhat.com" },
{ name="Eric Curtin", email = "ecurtin@redhat.com" },
]
description = "RamaLama is a command line tool for working with AI LLM models."
readme = "README.md"
license = {file = "LICENSE"}
keywords = ["ramalama", "llama", "AI"]
[project.optional-dependencies]
dev = [
"pytest>=7.0",
]
[project.urls]
Homepage = "https://github.com/containers/ramalama"
@@ -20,6 +30,12 @@ Documentation = "https://github.com/containers/ramalama/tree/main/docs"
Repository = "https://github.com/containers/ramalama"
Issues = "https://github.com/containers/ramalama/issues"
[project.scripts]
ramalama = "ramalama.cli:main"
[tool.setuptools]
include-package-data = true
[tool.black]
line-length = 120
skip-string-normalization = true
@@ -39,6 +55,7 @@ exclude = '''
| venv
)/
'''
[tool.isort]
profile = "black"
line_length = 120
@@ -52,3 +69,22 @@ log_cli = true
log_cli_level = "DEBUG"
log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
log_cli_date_format = "%Y-%m-%d %H:%M:%S"
[tool.setuptools.packages.find]
include = ["ramalama"]
[tool.setuptools.data-files]
"share/ramalama" = ["shortnames/shortnames.conf"]
"share/man/man1" = ["docs/*.1"]
"share/man/man5" = ["docs/*.5"]
"share/man/man7" = ["docs/*.7"]
"share/bash-completion/completions" = ["completions/bash-completion/completions/*"]
"share/zsh/vendor-completions" = ["completions/zsh/vendor-completions/*"]
"share/fish/vendor_completions.d" = ["completions/fish/vendor_completions.d/*"]
"libexec/ramalama" = [
"libexec/ramalama/ramalama-client-core",
"libexec/ramalama/ramalama-run-core",
"libexec/ramalama/ramalama-serve-core",
]

View File

@@ -1,8 +1,12 @@
import argparse
import errno
import glob
import json
import os
import shlex
import subprocess
import sys
import urllib
from datetime import datetime, timezone
from pathlib import Path
@@ -19,6 +23,7 @@ import ramalama.oci
import ramalama.rag
from ramalama.common import accel_image, exec_cmd, get_accel, get_cmd_with_wrapper, perror
from ramalama.config import CONFIG
from ramalama.migrate import ModelStoreImport
from ramalama.model import MODEL_TYPES
from ramalama.model_factory import ModelFactory
from ramalama.model_store import GlobalModelStore
@@ -668,7 +673,6 @@ def _get_source_model(args):
def push_cli(args):
source_model = _get_source_model(args)
target = args.SOURCE
if args.TARGET:
@@ -1074,3 +1078,49 @@ def inspect_cli(args):
args.pull = "never"
model = New(args.MODEL, args)
model.inspect(args)
def main():
parser, args = init_cli()
try:
import argcomplete
argcomplete.autocomplete(parser)
except Exception:
pass
try:
ModelStoreImport(args.store).import_all()
except Exception as ex:
print(f"Failed to import models to new store: {ex}")
def eprint(e, exit_code):
perror("Error: " + str(e).strip("'\""))
sys.exit(exit_code)
try:
args.func(args)
except urllib.error.HTTPError as e:
eprint(f"pulling {e.geturl()} failed: {e}", errno.EINVAL)
except HelpException:
parser.print_help()
except AttributeError as e:
parser.print_usage()
print("ramalama: requires a subcommand")
if getattr(args, "debug", False):
raise e
except IndexError as e:
eprint(e, errno.EINVAL)
except KeyError as e:
eprint(e, 1)
except NotImplementedError as e:
eprint(e, errno.ENOTSUP)
except subprocess.CalledProcessError as e:
eprint(e, e.returncode)
except KeyboardInterrupt:
sys.exit(0)
except ValueError as e:
eprint(e, errno.EINVAL)
except IOError as e:
eprint(e, errno.EIO)

View File

@@ -11,7 +11,6 @@ from ramalama.console import EMOJI
class Engine:
def __init__(self, args):
self.exec_args = [
args.engine,

View File

@@ -103,7 +103,6 @@ class ParseError(Exception):
class GGUFInfoParser:
def is_model_gguf(model_path: str) -> bool:
try:
with open(model_path, "rb") as model_file:

View File

@@ -167,7 +167,6 @@ GO_KEYWORDS: Dict[NodeType, re.Pattern] = {
def detect_node_type(stmt: str) -> Optional[NodeType]:
# from most complex to least
ordered_regex_list = [
(NodeType.RANGE, GO_KEYWORDS[NodeType.RANGE]),
@@ -196,7 +195,6 @@ def parse_go_template(content: str) -> list[Node]:
start_pos = content.find(GO_SYMBOL_OPEN_BRACKETS)
end_pos = 0
while start_pos != -1:
if end_pos == 0 and start_pos != 0:
content_node = Node(
end_pos,
@@ -319,8 +317,10 @@ def translate_continue_nodes(root_nodes: list[Node]) -> list[Node]:
if_node = Node(
-1,
-1,
f"{GO_SYMBOL_OPEN_BRACKETS} {NodeType.IF.value} {FunctionType.NEQUALS.value} {skip_variable} 1 "
f"{GO_SYMBOL_CLOSE_BRACKETS}",
(
f"{GO_SYMBOL_OPEN_BRACKETS} {NodeType.IF.value} {FunctionType.NEQUALS.value} {skip_variable} 1 "
f"{GO_SYMBOL_CLOSE_BRACKETS}"
),
NodeType.IF,
prev=to_wrap[0].prev,
next=to_wrap[0],
@@ -363,8 +363,10 @@ def translate_continue_nodes(root_nodes: list[Node]) -> list[Node]:
initial_set_node = Node(
-1,
-1,
f"{GO_SYMBOL_OPEN_BRACKETS}{SYMBOL_REMOVE_WHITESPACE} {skip_variable} := 0"
f"{SYMBOL_REMOVE_WHITESPACE}{GO_SYMBOL_CLOSE_BRACKETS}",
(
f"{GO_SYMBOL_OPEN_BRACKETS}{SYMBOL_REMOVE_WHITESPACE} {skip_variable} := 0"
f"{SYMBOL_REMOVE_WHITESPACE}{GO_SYMBOL_CLOSE_BRACKETS}"
),
NodeType.ASSIGNMENT,
prev=for_node,
next=for_node.next,
@@ -440,7 +442,6 @@ def go_to_jinja(content: str) -> str:
return transform_go_var_to_jinja(var, False).replace("$", "").lower()
def parse_pipeline(pipeline: str) -> str:
def parse_variable(pipeline: str) -> str:
reg = re.compile(R"{}".format(f"{REGEX_VARIABLE}"))
m = reg.match(pipeline)
@@ -611,7 +612,7 @@ def tree_structure(nodes: list[Node], level: int) -> str:
res = ""
for node in nodes:
parent_type = "--" if node.parent is None else node.parent.type
res += level * "\t" + f"{node.type}: {node.start},{node.end} - " f"{parent_type} - {node.content}\n"
res += level * "\t" + f"{node.type}: {node.start},{node.end} - {parent_type} - {node.content}\n"
res += tree_structure(node.children, level + 1)
return res

View File

@@ -41,7 +41,6 @@ def fetch_checksum_from_api(organization, file):
class HuggingfaceCLIFile(SnapshotFile):
def __init__(
self, url, header, hash, name, type, should_show_progress=False, should_verify_checksum=False, required=True
):
@@ -54,7 +53,6 @@ class HuggingfaceCLIFile(SnapshotFile):
class HuggingfaceRepository:
REGISTRY_URL = "https://huggingface.co"
FILE_NAME_CONFIG = "config.json"
@@ -148,7 +146,6 @@ def handle_repo_info(repo_name, repo_info, runtime):
class Huggingface(Model):
REGISTRY_URL = "https://huggingface.co/v2/"
ACCEPT = "Accept: application/vnd.docker.distribution.manifest.v2+json"
@@ -202,7 +199,6 @@ class Huggingface(Model):
# First try to interpret the argument as a user/repo:tag
try:
if self.directory.count("/") == 0:
model_name, model_tag, _ = self.extract_model_identifiers()
repo_name = self.directory + "/" + model_name
registry_head = f"{Huggingface.REGISTRY_URL}{repo_name}"

View File

@@ -19,7 +19,6 @@ class dotdict(dict):
class ModelStoreImport:
def __init__(self, store_path: str):
self.store_path = store_path
self._old_model_path = os.path.join(store_path, "models")
@@ -27,7 +26,6 @@ class ModelStoreImport:
self._global_store = GlobalModelStore(self.store_path)
class LocalModelFile(SnapshotFile):
def __init__(
self, url, header, hash, name, should_show_progress=False, should_verify_checksum=False, required=True
):

View File

@@ -47,7 +47,6 @@ $(error)s"""
class ModelBase:
def __not_implemented_error(self, param):
return NotImplementedError(f"ramalama {param} for '{type(self).__name__}' not implemented")

View File

@@ -13,7 +13,6 @@ from ramalama.url import URL
class ModelFactory:
def __init__(
self,
model: str,

View File

@@ -50,7 +50,6 @@ class ModelInfoBase:
class GGUFModelInfo(ModelInfoBase):
MAGIC_NUMBER = "GGUF"
VERSION = 3

View File

@@ -28,7 +28,6 @@ class SnapshotFileType(IntEnum):
class SnapshotFile:
def __init__(
self,
url: str,
@@ -60,7 +59,6 @@ class SnapshotFile:
class LocalSnapshotFile(SnapshotFile):
def __init__(
self,
content: str,
@@ -98,7 +96,6 @@ def validate_snapshot_files(snapshot_files: list[SnapshotFile]):
class RefFile:
SEP = "---"
MODEL_SUFFIX = "model"
CHAT_TEMPLATE_SUFFIX = "chat"
@@ -184,7 +181,6 @@ class dotdict(dict):
class GlobalModelStore:
def __init__(
self,
base_path: Path,
@@ -266,7 +262,6 @@ class GlobalModelStore:
class ModelStore:
def __init__(
self,
store: GlobalModelStore,

View File

@@ -33,8 +33,10 @@ def list_manifests(args):
"--filter",
"manifest=true",
"--format",
'{"name":"oci://{{ .Repository }}:{{ .Tag }}","modified":"{{ .CreatedAt }}",\
"size":{{ .VirtualSize }}, "ID":"{{ .ID }}"},',
(
'{"name":"oci://{{ .Repository }}:{{ .Tag }}","modified":"{{ .CreatedAt }}", "size":{{ .VirtualSize'
' }}, "ID":"{{ .ID }}"},'
),
]
output = run_cmd(conman_args, debug=args.debug).stdout.decode("utf-8").strip()
if output == "":
@@ -161,7 +163,7 @@ class OCI(Model):
registry, reference = model.split("/", 1)
except Exception:
raise KeyError(
f"You must specify a registry for the model in the form "
"You must specify a registry for the model in the form "
f"'oci://registry.acme.org/ns/repo:tag', got instead: {self.model}"
)

View File

@@ -33,7 +33,6 @@ def in_existing_cache(model_name, model_tag):
class OllamaRepository:
REGISTRY_URL = "https://registry.ollama.ai/v2/library"
ACCEPT = "Accept: application/vnd.docker.distribution.manifest.v2+json"

View File

@@ -25,7 +25,7 @@ class Shortnames:
self.paths = []
for file_path in file_paths:
config = configparser.ConfigParser(delimiters=("="))
config = configparser.ConfigParser(delimiters="=")
config.read(file_path)
if "shortnames" in config:
self.paths.append(os.path.realpath(file_path))

View File

@@ -1,97 +0,0 @@
import os
import setuptools
from setuptools import find_packages
from setuptools.command.build_py import build_py as build_py_orig
def generate_man1_pages(share_path, docs):
data_files = []
for path, _, files in os.walk(docs):
list_entry = (share_path, [os.path.join(path, f) for f in files if f.endswith(".1")])
data_files.append(list_entry)
return data_files
def generate_man5_pages(share_path, docs):
data_files = []
for path, _, files in os.walk(docs):
list_entry = (share_path, [os.path.join(path, f) for f in files if f.endswith(".5")])
data_files.append(list_entry)
return data_files
def generate_man7_pages(share_path, docs):
data_files = []
for path, _, files in os.walk(docs):
list_entry = (share_path, [os.path.join(path, f) for f in files if f.endswith(".7")])
data_files.append(list_entry)
return data_files
def generate_ramalama_conf(share_path, docs):
data_files = []
for path, _, files in os.walk(docs):
list_entry = (share_path, [os.path.join(path, f) for f in files if f.endswith(".conf")])
data_files.append(list_entry)
return data_files
def generate_completions(share_path, completions):
data_files = []
def remove_prefix(s, prefix):
if s.startswith(prefix):
length = len(prefix) + 1
return s[length:]
else:
return s
for path, _, files in os.walk(completions):
if len(files) == 0:
continue
list_entry = (
os.path.join(share_path, remove_prefix(path, completions)),
[os.path.join(path, f) for f in files],
)
data_files.append(list_entry)
return data_files
class build_py(build_py_orig):
def find_package_modules(self, package, package_dir):
modules = super().find_package_modules(package, package_dir)
return [(pkg, mod, file) for (pkg, mod, file) in modules]
setuptools.setup(
name="ramalama",
version="0.8.2",
packages=find_packages(),
cmdclass={"build_py": build_py},
scripts=["bin/ramalama"],
data_files=[("share/ramalama", ["shortnames/shortnames.conf"])]
+ generate_completions("share", "completions")
+ generate_ramalama_conf("share/ramalama", "docs")
+ generate_man1_pages("share/man/man1", "docs")
+ generate_man5_pages("share/man/man5", "docs")
+ generate_man7_pages("share/man/man7", "docs")
+ [
(
"libexec/ramalama",
[
"libexec/ramalama/ramalama-client-core",
"libexec/ramalama/ramalama-run-core",
"libexec/ramalama/ramalama-serve-core",
],
)
],
)