Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions .github/workflows/check-import-mappings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
name: Check Import Mappings

on:
schedule:
# Run every 3 days at midnight UTC
- cron: "0 0 */3 * *"
workflow_dispatch: # Allow manual trigger

jobs:
check-mappings:
name: Check langchain_core re-exports in langchain
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
steps:
- uses: actions/checkout@v5

- name: Set up Python 3.13 + uv
uses: "./.github/actions/uv_setup"
with:
python-version: "3.13"

- name: Install dependencies
run: |
uv sync --group test

- name: Check import mappings
run: |
uv run scripts/check_import_mappings.py

- name: Upload import mappings as artifact
uses: actions/upload-artifact@v4
with:
name: import-mappings
path: |
import_mappings.json
retention-days: 7

commit-mappings:
name: PR updated import mappings
needs: check-mappings
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v5

- name: Download updated files
uses: actions/download-artifact@v4
with:
name: import-mappings
path: .

- name: PR with changes
env:
GH_TOKEN: ${{ github.token }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"

# Check for changes
if [ ! -f import_mappings.json ]; then
echo "No import mappings file generated"
exit 0
fi

if [ ! -s import_mappings.json ]; then
echo "Empty import mappings file"
exit 0
fi

# Create branch with timestamp
BRANCH_NAME="chore/update-import-mappings-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$BRANCH_NAME"

# Commit changes
git add import_mappings.json
git commit -m "$(cat <<'EOF'
chore: update `langchain_core` import mappings

🤖 Automated analysis of `langchain_core` re-exports in `langchain` package

Generated with GitHub Actions workflow `check-import-mappings.yml`
EOF
)"

git push origin "$BRANCH_NAME"
gh pr create \
--title "chore: update `langchain_core` import mappings" \
--body "$(cat <<'EOF'
## Summary
Automated analysis of `langchain_core` re-exports in `langchain` package

## Details
- Analyzes latest releases of `langchain` and `langchain_core` from PyPI
- Identifies all members re-exported from `langchain_core` in `langchain` public `__init__` files
- Stores results in `import_mappings.json`
- Generated by GitHub Actions workflow `check-import-mappings.yml`
- Scheduled to run every 3 days at midnight UTC

🤖 This PR was created automatically by GitHub Actions
EOF
)" \
--base main \
--head "$BRANCH_NAME"
139 changes: 139 additions & 0 deletions .github/workflows/check-pr-imports.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
name: Check PR Imports

on:
pull_request:
branches: [main]
paths:
- "**/*.py"
- "**/*.md"
- "**/*.ipynb"

jobs:
check-imports:
name: Check for incorrect langchain_core imports
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0 # Need full history to compare with base branch

- name: Set up Python 3.13 + uv
uses: "./.github/actions/uv_setup"
with:
python-version: "3.13"

- name: Install dependencies
run: |
uv sync --group test

- name: Ensure import mappings exist
id: check-mappings
run: |
if [ -f "import_mappings.json" ]; then
echo "mappings_exist=true" >> $GITHUB_OUTPUT
else
echo "mappings_exist=false" >> $GITHUB_OUTPUT
fi

- name: Generate import mappings if missing
if: steps.check-mappings.outputs.mappings_exist == 'false'
run: |
echo "Import mappings not found, generating..."
uv run scripts/check_import_mappings.py

- name: Check PR
id: check-imports
run: |
if uv run scripts/check_pr_imports.py > import_check_output.txt 2>&1; then
echo "check_passed=true" >> $GITHUB_OUTPUT
echo "No import issues found"
else
echo "check_passed=false" >> $GITHUB_OUTPUT
echo "Import issues found"
cat import_check_output.txt
fi

- name: Comment on PR with issues
if: steps.check-imports.outputs.check_passed == 'false'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
let output = '';
try {
output = fs.readFileSync('import_check_output.txt', 'utf8');
} catch (error) {
output = 'Error reading import check output';
}

const body = `## ❌ Import check failed

This PR contains imports from \`langchain_core\` that should be imported from \`langchain\` instead.

<details>
<summary>Detailed issues</summary>

\`\`\`
${output}
\`\`\`

</details>

### Why this is a problem

The \`langchain\` package re-exports many modules and classes from \`langchain_core\`. When possible, imports should use \`langchain\` instead of \`langchain_core\` for:
- Better user experience (single import source)
- Consistency across documentation
- Reduced cognitive load for users

### How to fix

Replace the imports as suggested above. For example:
- ❌ \`from langchain_core.messages import HumanMessage\`
- ✅ \`from langchain.messages import HumanMessage\`

### 🤖 Automated check

This check is based on the latest analysis of \`langchain\` re-exports from \`langchain_core\`.
`;

// Check if we already commented
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});

const botComment = comments.data.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('Import Check Failed')
);

if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: body
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
}

- name: Fail the check if issues found
if: steps.check-imports.outputs.check_passed == 'false'
run: |
echo "❌ Import check failed. Please fix the issues above."
exit 1
1 change: 1 addition & 0 deletions scripts/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Scripts."""
Loading
Loading