Compare commits

...

8 Commits

Author SHA1 Message Date
github-actions[bot] 9ec2a8322e chore: version packages (#952) 2025-10-03 15:11:14 -06:00
Logan 51011b9f30 fix changeset harder (#951) 2025-10-03 15:09:58 -06:00
Logan 09805f9e15 swap changesets (#949) 2025-10-03 15:06:00 -06:00
Adrian Lyjak 8ced6f6eab fix: explicitly tag. I thought the action did this (#948) 2025-10-03 16:59:41 -04:00
Preston Carlson 081ddeca34 Escaping dollar signs in md output when running in a jupyter notebook (#945) 2025-10-03 14:52:26 -06:00
Adrian Lyjak 2460908789 Disable npm release (#946) 2025-10-03 16:13:16 -04:00
Adrian Lyjak c226d6a54c Fix more bugs in publishing (#944) 2025-10-03 11:16:43 -04:00
Adrian Lyjak 5d4c682eb2 fix: theres just one publish token (#943) 2025-10-03 10:56:10 -04:00
9 changed files with 90 additions and 58 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
"scripts": {
"pre-commit-version": "pnpm changeset",
"version": "./scripts/changeset-version.py version",
"publish": "./scripts/changeset-version.py publish"
"publish": "./scripts/changeset-version.py publish --no-js --tag"
},
"devDependencies": {
"prettier": "^3.6.2",
+6
View File
@@ -1,5 +1,11 @@
# llama-cloud-services-py
## 0.6.71
### Patch Changes
- 51011b9: Escape dollar signs in jupyter notebooks
## 0.6.70
### Patch Changes
+35 -6
View File
@@ -4,7 +4,10 @@ import re
from pydantic import BaseModel, Field, SerializeAsAny
from typing import Dict, Any, List, Optional
from llama_cloud_services.parse.utils import make_api_request
from llama_cloud_services.parse.utils import (
make_api_request,
is_jupyter,
)
from llama_index.core.async_utils import asyncio_run
from llama_index.core.schema import Document, ImageDocument, ImageNode, TextNode
@@ -258,6 +261,24 @@ class JobResult(BaseModel):
documents = await self.aget_text_documents(split_by_page)
return [TextNode(text=doc.text, metadata=doc.metadata) for doc in documents]
def _format_markdown_for_notebook(self, text: Optional[str]) -> Optional[str]:
"""Format markdown text for Jupyter notebook display by escaping dollar signs."""
if text is None:
return None
def escape_dollar_signs(text: str) -> str:
"""Escape dollar signs in text to prevent Jupyter from interpreting them as LaTeX.
Args:
text: The text to escape
Returns:
Text with dollar signs escaped
"""
return text.replace("$", r"\$")
return escape_dollar_signs(text)
def get_markdown_documents(self, split_by_page: bool = False) -> List[Document]:
"""
Get the markdown documents from the job.
@@ -268,17 +289,22 @@ class JobResult(BaseModel):
if split_by_page:
return [
Document(
text=page.md,
text=self._format_markdown_for_notebook(page.md)
if is_jupyter()
else page.md,
metadata={"page_number": page.page, "file_name": self.file_name},
)
for page in self.pages
]
else:
text = self._page_separator.join(
[page.md if page.md is not None else "" for page in self.pages]
)
return [
Document(
text=self._page_separator.join(
[page.md if page.md is not None else "" for page in self.pages]
),
text=self._format_markdown_for_notebook(text)
if is_jupyter()
else text,
metadata={"file_name": self.file_name},
)
]
@@ -328,7 +354,10 @@ class JobResult(BaseModel):
"""
url = f"{self._base_url}/api/v1/parsing/job/{self.job_id}/result/raw/markdown"
response = await make_api_request(self._client, "GET", url)
return response.content.decode("utf-8")
markdown = response.content.decode("utf-8")
return (
self._format_markdown_for_notebook(markdown) if is_jupyter() else markdown
)
def get_text(self) -> str:
"""
+12
View File
@@ -1,3 +1,4 @@
import functools
import httpx
import itertools
import logging
@@ -356,6 +357,17 @@ def partition_pages(
return
@functools.lru_cache(maxsize=1)
def is_jupyter() -> bool:
"""Check if we're running in a Jupyter environment."""
try:
from IPython import get_ipython
return get_ipython().__class__.__name__ == "ZMQInteractiveShell"
except (ImportError, AttributeError):
return False
def extract_tables_from_json_results(
json_results: List[dict], download_path: str
) -> List[str]:
+2 -2
View File
@@ -11,13 +11,13 @@ dev = [
[project]
name = "llama-parse"
version = "0.6.70"
version = "0.6.71"
description = "Parse files into RAG-Optimized formats."
authors = [{name = "Logan Markewich", email = "logan@llamaindex.ai"}]
requires-python = ">=3.9,<4.0"
readme = "README.md"
license = "MIT"
dependencies = ["llama-cloud-services>=0.6.70"]
dependencies = ["llama-cloud-services>=0.6.71"]
[project.scripts]
llama-parse = "llama_parse.cli.main:parse"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "llama-cloud-services-py",
"version": "0.6.70",
"version": "0.6.71",
"private": "true",
"license": "MIT",
"scripts": {}
+1 -1
View File
@@ -19,7 +19,7 @@ dev = [
[project]
name = "llama-cloud-services"
version = "0.6.70"
version = "0.6.71"
description = "Tailored SDK clients for LlamaCloud services."
authors = [{name = "Logan Markewich", email = "logan@runllama.ai"}]
requires-python = ">=3.9,<4.0"
Generated
+2 -2
View File
@@ -1,5 +1,5 @@
version = 1
revision = 2
revision = 3
requires-python = ">=3.9, <4.0"
resolution-markers = [
"python_full_version >= '3.14'",
@@ -1596,7 +1596,7 @@ wheels = [
[[package]]
name = "llama-cloud-services"
version = "0.6.69"
version = "0.6.70"
source = { editable = "." }
dependencies = [
{ name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+30 -45
View File
@@ -27,12 +27,10 @@ from packaging.version import Version
def _run_command(
cmd: List[str], check: bool = True, capture: bool = True, cwd: Path | None = None
) -> subprocess.CompletedProcess:
"""Run a command and return the result."""
return subprocess.run(
cmd, check=check, capture_output=capture, text=True, cwd=cwd or Path.cwd()
)
cmd: List[str], cwd: Path | None = None, env: dict[str, str] | None = None
) -> None:
"""Run a command, streaming output to the console, and raise on failure."""
subprocess.run(cmd, check=True, text=True, cwd=cwd or Path.cwd(), env=env)
def update_python_versions(version: str) -> None:
@@ -74,7 +72,7 @@ def update_python_versions(version: str) -> None:
def lock_python_dependencies() -> None:
"""Lock Python dependencies."""
try:
_run_command(["uv", "lock"], capture=False)
_run_command(["uv", "lock"])
click.echo("Locked Python dependencies")
except subprocess.CalledProcessError as e:
click.echo(f"Warning: Failed to lock Python dependencies: {e}", err=True)
@@ -90,7 +88,7 @@ def cli() -> None:
def version() -> None:
"""Apply changeset versions, and propagate them to Python packages."""
# First, run changeset version to update all package.json files (including py/package.json)
_run_command(["npx", "@changesets/cli", "version"], capture=False, check=True)
_run_command(["npx", "@changesets/cli", "version"])
# Get the updated Python package version from py/package.json (updated by changesets)
py_package_path = Path("py/package.json")
@@ -111,7 +109,9 @@ def version() -> None:
@cli.command()
@click.option("--tag", is_flag=True, help="Tag the packages after publishing")
@click.option("--dry-run", is_flag=True, help="Dry run the publish")
def publish(tag: bool, dry_run: bool) -> None:
@click.option("--js/--no-js", default=True, help="Publish the js package")
@click.option("--py/--no-py", default=True, help="Publish the py package")
def publish(tag: bool, dry_run: bool, js: bool, py: bool) -> None:
"""Publish all packages."""
# move to the root
os.chdir(Path(__file__).parent.parent)
@@ -119,16 +119,15 @@ def publish(tag: bool, dry_run: bool) -> None:
if not os.getenv("NPM_TOKEN"):
click.echo("NPM_TOKEN is not set, skipping publish", err=True)
raise click.Abort("No token set")
if not os.getenv("UV_PUBLISH_TOKEN"):
click.echo("UV_PUBLISH_TOKEN is not set, skipping publish", err=True)
raise click.Abort("No token set")
if not os.getenv("LLAMA_PARSE_PYPI_TOKEN"):
click.echo("LLAMA_PARSE_PYPI_TOKEN is not set, skipping publish", err=True)
raise click.Abort("No token set")
# not general script. Just checks each of the 2 packages to see if they need to be published.
maybe_publish_ts_package(dry_run)
maybe_publish_py_packages(dry_run)
if js:
maybe_publish_npm(dry_run)
if py:
maybe_publish_pypi(dry_run)
if tag:
if dry_run:
@@ -137,11 +136,11 @@ def publish(tag: bool, dry_run: bool) -> None:
click.echo(" git push --tags")
return
else:
_run_command(["npx", "@changesets/cli", "tag"], check=True, capture=True)
_run_command(["git", "push", "--tags"], check=True, capture=True)
_run_command(["npx", "@changesets/cli", "tag"])
_run_command(["git", "push", "--tags"])
def maybe_publish_ts_package(dry_run: bool) -> None:
def maybe_publish_npm(dry_run: bool) -> None:
"""Publish the ts package if it needs to be published."""
target_dir = Path("ts/llama_cloud_services")
ts_path_package = target_dir / "package.json"
@@ -149,10 +148,11 @@ def maybe_publish_ts_package(dry_run: bool) -> None:
version = package_json["version"]
# Check if this version is already published on npm
result = _run_command(
result = subprocess.run(
["npm", "view", "llama-cloud-services", "versions", "--json"],
check=True,
capture=True,
capture_output=True,
text=True,
cwd=target_dir,
)
@@ -162,20 +162,18 @@ def maybe_publish_ts_package(dry_run: bool) -> None:
f"npm package llama-cloud-services@{version} already published, skipping"
)
return
click.echo(f"Publishing llama-cloud-services@{version}")
click.echo(f"Publishing npm package llama-cloud-services@{version}")
# defer to the package.json publish script
if dry_run:
click.echo("Dry run, skipping publish. Would run:")
click.echo(" pnpm run publish")
return
else:
output = _run_command(
["pnpm", "runpublish"], check=True, capture=True, cwd=target_dir
)
click.echo(output.stdout)
_run_command(["pnpm", "run", "build"], cwd=target_dir)
_run_command(["pnpm", "publish"], cwd=target_dir)
def maybe_publish_py_packages(dry_run: bool) -> None:
def maybe_publish_pypi(dry_run: bool) -> None:
"""Publish the py packages if they need to be published."""
for pyproject in list(Path("py").glob("*/pyproject.toml")) + [
Path("py/pyproject.toml")
@@ -184,35 +182,22 @@ def maybe_publish_py_packages(dry_run: bool) -> None:
if is_published(name, version):
click.echo(f"PyPI package {name}@{version} already published, skipping")
continue
click.echo(f"Publishing {name}@{version}")
click.echo(f"Publishing PyPI package {name}@{version}")
# Use different tokens for different packages
env = os.environ.copy()
if name == "llama-parse":
# llama-parse uses its own token
env["UV_PUBLISH_TOKEN"] = os.environ["LLAMA_PARSE_PYPI_TOKEN"]
else:
# llama-cloud-services uses the main PyPI token
env["UV_PUBLISH_TOKEN"] = os.environ["UV_PUBLISH_TOKEN"]
token = os.environ["LLAMA_PARSE_PYPI_TOKEN"]
env["UV_PUBLISH_TOKEN"] = token
if dry_run:
token = env["UV_PUBLISH_TOKEN"]
summary = (token[:3] + "***") if len(token) <= 6 else token[:6] + "****"
click.echo(
f"Dry run, skipping publish. Would run with publish token {summary}:"
)
click.echo(" uv publish --dry-run")
return
click.echo(" uv build")
click.echo(" uv publish")
else:
result = subprocess.run(
["uv", "publish"],
check=True,
capture_output=True,
text=True,
cwd=pyproject.parent,
env=env,
)
click.echo(result.stdout)
_run_command(["uv", "build"], cwd=pyproject.parent)
_run_command(["uv", "publish"], cwd=pyproject.parent, env=env)
def current_version(pyproject: Path) -> tuple[str, str]: