From 041c89fed69905a55814463186edbc4fecd77d3d Mon Sep 17 00:00:00 2001 From: Vishal Shenoy Date: Tue, 28 Jan 2025 17:08:09 -0800 Subject: [PATCH 1/4] remove unnecessary stuff --- examples/sqlalchemy_1.6_to_2.0/guide.md | 96 ----------------- .../output_repo/database.py | 10 -- .../sqlalchemy_1.6_to_2.0/output_repo/main.py | 102 ------------------ .../output_repo/models.py | 32 ------ .../output_repo/schemas.py | 31 ------ 5 files changed, 271 deletions(-) delete mode 100644 examples/sqlalchemy_1.6_to_2.0/guide.md delete mode 100644 examples/sqlalchemy_1.6_to_2.0/output_repo/database.py delete mode 100644 examples/sqlalchemy_1.6_to_2.0/output_repo/main.py delete mode 100644 examples/sqlalchemy_1.6_to_2.0/output_repo/models.py delete mode 100644 examples/sqlalchemy_1.6_to_2.0/output_repo/schemas.py diff --git a/examples/sqlalchemy_1.6_to_2.0/guide.md b/examples/sqlalchemy_1.6_to_2.0/guide.md deleted file mode 100644 index 9135dac..0000000 --- a/examples/sqlalchemy_1.6_to_2.0/guide.md +++ /dev/null @@ -1,96 +0,0 @@ -# Guide: Migrating from SQLAlchemy 1.6 to 2.0 with Codegen - -This guide walks you through the steps to migrate your codebase from SQLAlchemy 1.6 to 2.0 using Codegen. Follow along to modernize your imports, relationships, and query syntax while ensuring compatibility with SQLAlchemy 2.0. Each step includes a direct link to the appropriate codemod for easy implementation. - ---- - -## 🎉 Overview of Changes - -The migration focuses on these key updates: - -1. **Import Adjustments** - Aligns your code with the updated SQLAlchemy 2.0 module structure. - [Run the Import Codemod](https://www.codegen.sh/search/6506?skillType=codemod) - -2. **Relationship Updates** - Refines relationship definitions by replacing `backref` with `back_populates` for explicitness and better readability. - [Run the Relationship Codemod](https://www.codegen.sh/search/6510?skillType=codemod) - -3. **Query Syntax Modernization** - Updates queries to leverage the latest syntax like `select()` and `where()`, removing deprecated methods. - [Run the Query Syntax Codemod](https://www.codegen.sh/search/6508?skillType=codemod) - -4. **Relationship Lazy Loading** - SQLAlchemy 2.0 introduces a new `lazy` parameter for relationship definitions. Update your relationships to use the new `lazy` parameter for improved performance. - [Run the Relationship Lazy Loading Codemod](https://www.codegen.sh/search/6512?skillType=codemod) - -5. **Type Annotations** - SQLAlchemy 2.0 has improved type annotation support. Update your models to include type hints for better IDE support and runtime type checking. - - - Add type annotations to model attributes and relationships - - Leverage SQLAlchemy's typing module for proper type hints - - Enable better IDE autocompletion and type checking - - [Run the Type Annotations Codemod](https://www.codegen.sh/search/4645?skillType=codemod) - ---- - -## How to Migrate - -### Step 1: Update Imports - -SQLAlchemy 2.0 introduces a refined import structure. Use the import codemod to: - -- Replace wildcard imports (`*`) with explicit imports for better clarity. -- Update `declarative_base` to `DeclarativeBase`. - -👉 [Run the Import Codemod](https://www.codegen.sh/search/6506?skillType=codemod) - ---- - -### Step 2: Refactor Relationships - -In SQLAlchemy 2.0, relationships require more explicit definitions. This includes: - -- Transitioning from `backref` to `back_populates` for consistency. -- Explicitly specifying `back_populates` for all relationship definitions. - -👉 [Run the Relationship Codemod](https://www.codegen.sh/search/6510?skillType=codemod) - ---- - -### Step 3: Modernize Query Syntax - -The query API has been revamped in SQLAlchemy 2.0. Key updates include: - -- Switching to `select()` and `where()` for query construction. -- Replacing any deprecated methods with their modern equivalents. - -👉 [Run the Query Syntax Codemod](https://www.codegen.sh/search/6508?skillType=codemod) - ---- - -### Step 4: Update Relationship Lazy Loading - -SQLAlchemy 2.0 introduces a new `lazy` parameter for relationship definitions. Update your relationships to use the new `lazy` parameter for improved performance. - -👉 [Run the Relationship Lazy Loading Codemod](https://www.codegen.sh/search/6512?skillType=codemod) - ---- - -### Step 5: Add Type Annotations -SQLAlchemy 2.0 has improved type annotation support. Update your models to include type hints for better IDE support and runtime type checking. - -- Add type annotations to model attributes and relationships -- Leverage SQLAlchemy's typing module for proper type hints -- Enable better IDE autocompletion and type checking - -👉 [Run the Type Annotations Codemod](https://www.codegen.sh/search/4645?skillType=codemod) - ---- - -## Need Help? - -If you encounter issues or have specific edge cases not addressed by the codemods, reach out to the Codegen support team or visit the [Codegen Documentation](https://www.codegen.sh/docs) for detailed guidance. - -Start your SQLAlchemy 2.0 migration today and enjoy the benefits of a cleaner, modern codebase! diff --git a/examples/sqlalchemy_1.6_to_2.0/output_repo/database.py b/examples/sqlalchemy_1.6_to_2.0/output_repo/database.py deleted file mode 100644 index 26ccd07..0000000 --- a/examples/sqlalchemy_1.6_to_2.0/output_repo/database.py +++ /dev/null @@ -1,10 +0,0 @@ -# database.py -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker - -SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/dbname" # Change to your database URL - -engine = create_engine(SQLALCHEMY_DATABASE_URL) -SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) - -Base = declarative_base() diff --git a/examples/sqlalchemy_1.6_to_2.0/output_repo/main.py b/examples/sqlalchemy_1.6_to_2.0/output_repo/main.py deleted file mode 100644 index 93a716f..0000000 --- a/examples/sqlalchemy_1.6_to_2.0/output_repo/main.py +++ /dev/null @@ -1,102 +0,0 @@ -# main.py -from fastapi import FastAPI, Depends, HTTPException -from sqlalchemy.orm import Session -import models -import schemas -from database import SessionLocal, engine -from typing import List - -# Initialize the app and create database tables -app = FastAPI() -models.Base.metadata.create_all(bind=engine) - -# Dependency for the database session -def get_db(): - db = SessionLocal() - try: - yield db - finally: - db.close() - -# CRUD Operations - -@app.post("/books/", response_model=schemas.Book) -def create_book(book: schemas.BookCreate, db: Session = Depends(get_db)): - db_book = models.Book(**book.dict()) - db.add(db_book) - db.commit() - db.refresh(db_book) - return db_book - -@app.get("/books/", response_model=List[schemas.Book]) -def read_books(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): - books = db.query()(models.Book).offset(skip).limit(limit).scalars().all() - return books - -@app.get("/books/{book_id}", response_model=schemas.Book) -def read_book(book_id: int, db: Session = Depends(get_db)): - book = db.query()(models.Book).where(models.Book.id == book_id).first() - if book is None: - raise HTTPException(status_code=404, detail="Book not found") - return book - -@app.put("/books/{book_id}", response_model=schemas.Book) -def update_book(book_id: int, book: schemas.BookCreate, db: Session = Depends(get_db)): - db_book = db.query()(models.Book).where(models.Book.id == book_id).first() - if db_book is None: - raise HTTPException(status_code=404, detail="Book not found") - for key, value in book.dict().items(): - setattr(db_book, key, value) - db.commit() - db.refresh(db_book) - return db_book - -@app.delete("/books/{book_id}", response_model=schemas.Book) -def delete_book(book_id: int, db: Session = Depends(get_db)): - db_book = db.query()(models.Book).where(models.Book.id == book_id).first() - if db_book is None: - raise HTTPException(status_code=404, detail="Book not found") - db.delete(db_book) - db.commit() - return db_book - -@app.post("/publishers/", response_model=schemas.Publisher) -def create_publisher(publisher: schemas.PublisherCreate, db: Session = Depends(get_db)): - db_publisher = models.Publisher(**publisher.dict()) - db.add(db_publisher) - db.commit() - db.refresh(db_publisher) - return db_publisher - -@app.get("/publishers/", response_model=List[schemas.Publisher]) -def read_publishers(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): - publishers = db.query()(models.Publisher).offset(skip).limit(limit).scalars().all() - return publishers - -@app.get("/publishers/{publisher_id}", response_model=schemas.Publisher) -def read_publisher(publisher_id: int, db: Session = Depends(get_db)): - publisher = db.query()(models.Publisher).where(models.Publisher.id == publisher_id).first() - if not publisher: - raise HTTPException(status_code=404, detail="Publisher not found") - return publisher - -@app.put("/publishers/{publisher_id}", response_model=schemas.Publisher) -def update_publisher(publisher_id: int, publisher: schemas.PublisherCreate, db: Session = Depends(get_db)): - db_publisher = db.query()(models.Publisher).where(models.Publisher.id == publisher_id).first() - if not db_publisher: - raise HTTPException(status_code=404, detail="Publisher not found") - for key, value in publisher.dict().items(): - setattr(db_publisher, key, value) - db.commit() - db.refresh(db_publisher) - return db_publisher - -@app.delete("/publishers/{publisher_id}", response_model=schemas.Publisher) -def delete_publisher(publisher_id: int, db: Session = Depends(get_db)): - db_publisher = db.query()(models.Publisher).where(models.Publisher.id == publisher_id).first() - if not db_publisher: - raise HTTPException(status_code=404, detail="Publisher not found") - db.delete(db_publisher) - db.commit() - return db_publisher - diff --git a/examples/sqlalchemy_1.6_to_2.0/output_repo/models.py b/examples/sqlalchemy_1.6_to_2.0/output_repo/models.py deleted file mode 100644 index d6fcceb..0000000 --- a/examples/sqlalchemy_1.6_to_2.0/output_repo/models.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import List, Optional -from sqlalchemy import Integer, String, ForeignKey -from sqlalchemy.orm import relationship, Mapped, mapped_column -from database import Base - -class Publisher(Base): - __tablename__ = "publishers" - - id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) - name: Mapped[str] = mapped_column(String, unique=True, index=True) - books: Mapped[List["Book"]] = relationship( - "Book", - back_populates="publisher", - lazy='selectin' - ) - -class Book(Base): - __tablename__ = "books" - - id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) - title: Mapped[str] = mapped_column(String, index=True) - author: Mapped[str] = mapped_column(String, index=True) - description: Mapped[Optional[str]] = mapped_column(String, nullable=True) - publisher_id: Mapped[Optional[int]] = mapped_column( - Integer, - ForeignKey("publishers.id"), - nullable=True - ) - publisher: Mapped[Optional["Publisher"]] = relationship( - "Publisher", - back_populates="books" - ) \ No newline at end of file diff --git a/examples/sqlalchemy_1.6_to_2.0/output_repo/schemas.py b/examples/sqlalchemy_1.6_to_2.0/output_repo/schemas.py deleted file mode 100644 index daf4fb9..0000000 --- a/examples/sqlalchemy_1.6_to_2.0/output_repo/schemas.py +++ /dev/null @@ -1,31 +0,0 @@ -from pydantic import BaseModel -from typing import List, Optional - -class PublisherBase(BaseModel): - name: str - -class PublisherCreate(PublisherBase): - pass - -class Publisher(PublisherBase): - id: int - books: List["Book"] = [] - - class Config: - orm_mode = True - -class BookBase(BaseModel): - title: str - author: str - description: str - publisher_id: Optional[int] - -class BookCreate(BookBase): - pass - -class Book(BookBase): - id: int - publisher: Optional[Publisher] - - class Config: - orm_mode = True From 6d8cb0451a1d705de6556f7d96e83f34c55db201 Mon Sep 17 00:00:00 2001 From: Vishal Shenoy Date: Tue, 28 Jan 2025 17:32:08 -0800 Subject: [PATCH 2/4] syntax --- examples/sqlalchemy_1.6_to_2.0/README.md | 17 +-- .../output_repo/database.py | 10 ++ .../sqlalchemy_1.6_to_2.0/output_repo/main.py | 102 ++++++++++++++++++ .../output_repo/models.py | 32 ++++++ .../output_repo/schemas.py | 31 ++++++ 5 files changed, 177 insertions(+), 15 deletions(-) create mode 100644 examples/sqlalchemy_1.6_to_2.0/output_repo/database.py create mode 100644 examples/sqlalchemy_1.6_to_2.0/output_repo/main.py create mode 100644 examples/sqlalchemy_1.6_to_2.0/output_repo/models.py create mode 100644 examples/sqlalchemy_1.6_to_2.0/output_repo/schemas.py diff --git a/examples/sqlalchemy_1.6_to_2.0/README.md b/examples/sqlalchemy_1.6_to_2.0/README.md index da0e1d8..746b064 100644 --- a/examples/sqlalchemy_1.6_to_2.0/README.md +++ b/examples/sqlalchemy_1.6_to_2.0/README.md @@ -60,23 +60,10 @@ The migration script handles four key transformations: addresses: Mapped[List["Address"]] = relationship() ``` -## Running the Example - -```bash -# Install Codegen -pip install codegen - -# Run the migration -python run.py -``` - -The script will process all Python files in the `repo-before` directory and apply the transformations in the correct order. - ## Understanding the Code -- `run.py` - The migration script -- `repo-before/` - Sample SQLAlchemy 1.6 application to migrate -- `guide.md` - Additional notes and explanations +- `input_repo` - Sample SQLAlchemy 1.6 application to migrate +- `output_repo` - Sample SQLAlchemy 2.0 application after migration ## Learn More diff --git a/examples/sqlalchemy_1.6_to_2.0/output_repo/database.py b/examples/sqlalchemy_1.6_to_2.0/output_repo/database.py new file mode 100644 index 0000000..26ccd07 --- /dev/null +++ b/examples/sqlalchemy_1.6_to_2.0/output_repo/database.py @@ -0,0 +1,10 @@ +# database.py +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/dbname" # Change to your database URL + +engine = create_engine(SQLALCHEMY_DATABASE_URL) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() diff --git a/examples/sqlalchemy_1.6_to_2.0/output_repo/main.py b/examples/sqlalchemy_1.6_to_2.0/output_repo/main.py new file mode 100644 index 0000000..93a716f --- /dev/null +++ b/examples/sqlalchemy_1.6_to_2.0/output_repo/main.py @@ -0,0 +1,102 @@ +# main.py +from fastapi import FastAPI, Depends, HTTPException +from sqlalchemy.orm import Session +import models +import schemas +from database import SessionLocal, engine +from typing import List + +# Initialize the app and create database tables +app = FastAPI() +models.Base.metadata.create_all(bind=engine) + +# Dependency for the database session +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + +# CRUD Operations + +@app.post("/books/", response_model=schemas.Book) +def create_book(book: schemas.BookCreate, db: Session = Depends(get_db)): + db_book = models.Book(**book.dict()) + db.add(db_book) + db.commit() + db.refresh(db_book) + return db_book + +@app.get("/books/", response_model=List[schemas.Book]) +def read_books(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): + books = db.query()(models.Book).offset(skip).limit(limit).scalars().all() + return books + +@app.get("/books/{book_id}", response_model=schemas.Book) +def read_book(book_id: int, db: Session = Depends(get_db)): + book = db.query()(models.Book).where(models.Book.id == book_id).first() + if book is None: + raise HTTPException(status_code=404, detail="Book not found") + return book + +@app.put("/books/{book_id}", response_model=schemas.Book) +def update_book(book_id: int, book: schemas.BookCreate, db: Session = Depends(get_db)): + db_book = db.query()(models.Book).where(models.Book.id == book_id).first() + if db_book is None: + raise HTTPException(status_code=404, detail="Book not found") + for key, value in book.dict().items(): + setattr(db_book, key, value) + db.commit() + db.refresh(db_book) + return db_book + +@app.delete("/books/{book_id}", response_model=schemas.Book) +def delete_book(book_id: int, db: Session = Depends(get_db)): + db_book = db.query()(models.Book).where(models.Book.id == book_id).first() + if db_book is None: + raise HTTPException(status_code=404, detail="Book not found") + db.delete(db_book) + db.commit() + return db_book + +@app.post("/publishers/", response_model=schemas.Publisher) +def create_publisher(publisher: schemas.PublisherCreate, db: Session = Depends(get_db)): + db_publisher = models.Publisher(**publisher.dict()) + db.add(db_publisher) + db.commit() + db.refresh(db_publisher) + return db_publisher + +@app.get("/publishers/", response_model=List[schemas.Publisher]) +def read_publishers(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): + publishers = db.query()(models.Publisher).offset(skip).limit(limit).scalars().all() + return publishers + +@app.get("/publishers/{publisher_id}", response_model=schemas.Publisher) +def read_publisher(publisher_id: int, db: Session = Depends(get_db)): + publisher = db.query()(models.Publisher).where(models.Publisher.id == publisher_id).first() + if not publisher: + raise HTTPException(status_code=404, detail="Publisher not found") + return publisher + +@app.put("/publishers/{publisher_id}", response_model=schemas.Publisher) +def update_publisher(publisher_id: int, publisher: schemas.PublisherCreate, db: Session = Depends(get_db)): + db_publisher = db.query()(models.Publisher).where(models.Publisher.id == publisher_id).first() + if not db_publisher: + raise HTTPException(status_code=404, detail="Publisher not found") + for key, value in publisher.dict().items(): + setattr(db_publisher, key, value) + db.commit() + db.refresh(db_publisher) + return db_publisher + +@app.delete("/publishers/{publisher_id}", response_model=schemas.Publisher) +def delete_publisher(publisher_id: int, db: Session = Depends(get_db)): + db_publisher = db.query()(models.Publisher).where(models.Publisher.id == publisher_id).first() + if not db_publisher: + raise HTTPException(status_code=404, detail="Publisher not found") + db.delete(db_publisher) + db.commit() + return db_publisher + diff --git a/examples/sqlalchemy_1.6_to_2.0/output_repo/models.py b/examples/sqlalchemy_1.6_to_2.0/output_repo/models.py new file mode 100644 index 0000000..d6fcceb --- /dev/null +++ b/examples/sqlalchemy_1.6_to_2.0/output_repo/models.py @@ -0,0 +1,32 @@ +from typing import List, Optional +from sqlalchemy import Integer, String, ForeignKey +from sqlalchemy.orm import relationship, Mapped, mapped_column +from database import Base + +class Publisher(Base): + __tablename__ = "publishers" + + id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) + name: Mapped[str] = mapped_column(String, unique=True, index=True) + books: Mapped[List["Book"]] = relationship( + "Book", + back_populates="publisher", + lazy='selectin' + ) + +class Book(Base): + __tablename__ = "books" + + id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) + title: Mapped[str] = mapped_column(String, index=True) + author: Mapped[str] = mapped_column(String, index=True) + description: Mapped[Optional[str]] = mapped_column(String, nullable=True) + publisher_id: Mapped[Optional[int]] = mapped_column( + Integer, + ForeignKey("publishers.id"), + nullable=True + ) + publisher: Mapped[Optional["Publisher"]] = relationship( + "Publisher", + back_populates="books" + ) \ No newline at end of file diff --git a/examples/sqlalchemy_1.6_to_2.0/output_repo/schemas.py b/examples/sqlalchemy_1.6_to_2.0/output_repo/schemas.py new file mode 100644 index 0000000..daf4fb9 --- /dev/null +++ b/examples/sqlalchemy_1.6_to_2.0/output_repo/schemas.py @@ -0,0 +1,31 @@ +from pydantic import BaseModel +from typing import List, Optional + +class PublisherBase(BaseModel): + name: str + +class PublisherCreate(PublisherBase): + pass + +class Publisher(PublisherBase): + id: int + books: List["Book"] = [] + + class Config: + orm_mode = True + +class BookBase(BaseModel): + title: str + author: str + description: str + publisher_id: Optional[int] + +class BookCreate(BookBase): + pass + +class Book(BookBase): + id: int + publisher: Optional[Publisher] + + class Config: + orm_mode = True From 20fb5e7d656a0be7d0028ced0c9034baad2ee9bf Mon Sep 17 00:00:00 2001 From: Vishal Shenoy Date: Tue, 28 Jan 2025 17:33:47 -0800 Subject: [PATCH 3/4] cleaning --- STRUCTURE.md | 2 +- examples/flask_to_fastapi_migration/README.md | 3 +-- examples/python2_to_python3/README.md | 3 +-- examples/unittest_to_pytest/README.md | 3 +-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/STRUCTURE.md b/STRUCTURE.md index 98372cf..204a083 100644 --- a/STRUCTURE.md +++ b/STRUCTURE.md @@ -16,7 +16,7 @@ example-name/ ├── README.md # Documentation and usage examples ├── run.py # Main implementation ├── guide.md # (Optional) Additional technical details -└── repo-before/ # (Optional) Sample code for transformation +└── input_repo/ # (Optional) Sample code for transformation ``` ## Code Organization in `run.py` diff --git a/examples/flask_to_fastapi_migration/README.md b/examples/flask_to_fastapi_migration/README.md index 3803f56..0b1b41b 100644 --- a/examples/flask_to_fastapi_migration/README.md +++ b/examples/flask_to_fastapi_migration/README.md @@ -63,8 +63,7 @@ The script will process all Python files in the `repo-before` directory and appl ## Understanding the Code - `run.py` - The migration script -- `repo-before/` - Sample Flask application to migrate -- `guide.md` - Additional notes and explanations +- `input_repo/` - Sample Flask application to migrate ## Learn More diff --git a/examples/python2_to_python3/README.md b/examples/python2_to_python3/README.md index f393861..cf342b7 100644 --- a/examples/python2_to_python3/README.md +++ b/examples/python2_to_python3/README.md @@ -83,8 +83,7 @@ The script will process all Python files in the `repo-before` directory and appl ## Understanding the Code - `run.py` - The migration script -- `repo-before/` - Sample Python 2 code to migrate -- `guide.md` - Additional notes and explanations +- `input_repo/` - Sample Python 2 code to migrate ## Learn More diff --git a/examples/unittest_to_pytest/README.md b/examples/unittest_to_pytest/README.md index 91095ca..ecf4e4a 100644 --- a/examples/unittest_to_pytest/README.md +++ b/examples/unittest_to_pytest/README.md @@ -89,8 +89,7 @@ The script will process all Python test files in the `repo-before` directory and ## Understanding the Code - `run.py` - The migration script -- `repo-before/` - Sample `unittest` test suite to migrate -- `guide.md` - Additional notes and explanations +- `input_repo/` - Sample `unittest` test suite to migrate ## Learn More From 3c208f70eb2dd850a406f3c884639c59dfc6476d Mon Sep 17 00:00:00 2001 From: vishalshenoy <34020235+vishalshenoy@users.noreply.github.com> Date: Wed, 29 Jan 2025 01:34:08 +0000 Subject: [PATCH 4/4] Automated pre-commit update --- STRUCTURE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STRUCTURE.md b/STRUCTURE.md index 204a083..be8da66 100644 --- a/STRUCTURE.md +++ b/STRUCTURE.md @@ -43,7 +43,7 @@ Your `run.py` should follow this structure, demonstrated well in the `generate_t @codegen.function("your-function-name") def run(codebase: Codebase): """Clear docstring explaining what the function does. - + Include: 1. Purpose of the function 2. Key steps or transformations @@ -128,7 +128,7 @@ def get_function_context(function) -> dict: @codegen.function("generate-training-data") def run(codebase: Codebase): """Generate training data using a node2vec-like approach... - + This codemod: 1. Finds all functions... 2. For each function...