docs: add 3rd party packages scaffold (#3263)

* Adds scaffolding for 3rd party packages. Not published yet.
This commit is contained in:
Eugene Yurtsev
2025-02-03 17:21:30 +00:00
committed by GitHub
parent 098d5ec403
commit 72ce34e3e6
4 changed files with 211 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
#!/usr/bin/env python
"""Create the third party page for the documentation."""
import argparse
from typing import List
from typing import TypedDict
import yaml
MARKDOWN = """\
# 🚀 Third-party Libraries
A collection of third-party libraries that extend LangGraph's functionality.
## 📚 Available Libraries
{library_list}
## ✨ Contributing Your Library
If you'd like to add your library to this list, please open a pull request on the {langgraph_url}.
Thanks for contributing! 🚀
"""
class ResolvedPackage(TypedDict):
name: str
"""The name of the package."""
repo: str
"""Repository ID within github. Format is: [orgname]/[repo_name]."""
weekly_downloads: int | None
"""The weekly download count of the package."""
description: str
"""A brief description of what the package does."""
def generate_markdown(resolved_packages: List[ResolvedPackage], language: str) -> str:
"""Generate the markdown content for the third party page.
Args:
resolved_packages: A list of resolved package information.
language: str
Returns:
The markdown content as a string.
"""
# Update the URL to the actual file once the initial version is merged
if language == "python":
langgraph_url = "https://github.com/langchain-ai/langgraph/pulls"
elif language == "js":
langgraph_url = "https://github.com/langchain-ai/langgraphjs/pulls"
else:
raise ValueError(f"Invalid language '{language}'. Expected 'python' or 'js'.")
sorted_packages = sorted(
resolved_packages, key=lambda p: p["weekly_downloads"] or 0, reverse=True
)
rows = [
"| Name | GitHub URL | Description | Downloads |",
"| --- | --- | --- | --- |",
]
for package in sorted_packages:
name = f"**{package['name']}**"
repo_url = f"[{package['repo']}](https://github.com/{package['repo']})"
downloads = package["weekly_downloads"] or 0
row = f"| {name} | {repo_url} | {package['description']} | {downloads} |"
rows.append(row)
markdown_content = MARKDOWN.format(
library_list="\n".join(rows), langgraph_url=langgraph_url
)
return markdown_content
def main(input_file: str, output_file: str, language: str) -> None:
"""Main function to create the third party page.
Args:
input_file: Path to the input YAML file containing resolved package information.
output_file: Path to the output file for the third party page.
language: The language for which to generate the third party page.
"""
# Parse the input YAML file
with open(input_file, "r") as f:
resolved_packages: List[ResolvedPackage] = yaml.safe_load(f)
markdown_content = generate_markdown(resolved_packages, language)
# Write the markdown content to the output file
with open(output_file, "w", encoding="utf-8") as f:
f.write(markdown_content)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Create the third party page.")
parser.add_argument(
"input_file",
help="Path to the input YAML file containing resolved package information.",
)
parser.add_argument(
"output_file", help="Path to the output file for the third party page."
)
parser.add_argument(
"--language",
choices=["python", "js"],
default="python",
help="The language for which to generate the third party page. Defaults to 'python'.",
)
args = parser.parse_args()
main(args.input_file, args.output_file, args.language)
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python
"""Retrieve download count for a list of Python packages from PyPI."""
import argparse
from datetime import datetime
from typing import TypedDict
import pathlib
import requests
import yaml
class Package(TypedDict):
"""A TypedDict representing a package"""
name: str
"""The name of the package."""
repo: str
"""Repository ID within github. Format is: [orgname]/[repo_name]."""
description: str
"""A brief description of what the package does."""
class ResolvedPackage(Package):
weekly_downloads: int | None
HERE = pathlib.Path(__file__).parent
PACKAGES_FILE = HERE / "packages.yml"
PACKAGES = yaml.safe_load(PACKAGES_FILE.read_text())['packages']
def _get_weekly_downloads(packages: list[Package]) -> list[ResolvedPackage]:
"""Retrieve the monthly download count for a list of packages from PyPIStats."""
resolved_packages: list[ResolvedPackage] = []
for package in packages:
url = f"https://pypistats.org/api/packages/{package['name']}/overall"
response = requests.get(url)
response.raise_for_status()
data = response.json()
sorted_data = sorted(
data["data"],
key=lambda x: datetime.strptime(x["date"], "%Y-%m-%d"),
reverse=True,
)
# Sum the last 7 days of downloads
num_downloads = sum(entry["downloads"] for entry in sorted_data[:7])
resolved_packages.append(
{
"name": package["name"],
"repo": package["repo"],
"weekly_downloads": num_downloads,
"description": package["description"],
}
)
return resolved_packages
def main(output_file: str) -> None:
"""Main function to generate package download information.
Args:
output_file: Path to the output YAML file.
"""
resolved_packages: list[ResolvedPackage] = _get_weekly_downloads(PACKAGES)
if not output_file.endswith(".yml"):
raise ValueError("Output file must have a .yml extension")
with open(output_file, "w") as f:
f.write("# This file is auto-generated. Do not edit.\n")
yaml.dump(resolved_packages, f)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Generate package download information."
)
parser.add_argument(
"output_file",
help=(
"Path to the output YAML file. Example: python generate_downloads.py "
"downloads.yml"
),
)
args = parser.parse_args()
main(args.output_file)
@@ -0,0 +1,5 @@
#A list of third-party packages to surface on the third-party page.
packages:
- name: "trustcall"
repo: "hinthornw/trustcall"
description: "Tenacious tool calling built on LangGraph"