diff --git a/flask_to_fastapi_migration/guide.md b/flask_to_fastapi_migration/guide.md deleted file mode 100644 index 929352d..0000000 --- a/flask_to_fastapi_migration/guide.md +++ /dev/null @@ -1,75 +0,0 @@ -# Guide: Migrating from Flask to FastAPI with Codegen - -This guide walks you through the steps to migrate your codebase from Flask to FastAPI using Codegen. Follow along to modernize your static file handling, template syntax, and routes while ensuring compatibility with FastAPI. Each step includes a direct link to the appropriate codemod for easy implementation. - ---- - -## 🎉 Overview of Changes - -The migration focuses on these key updates: - -1. **Static File Handling** - Migrate static file handling to FastAPI's approach. - [Run the Static File Handling Codemod](https://www.codegen.sh/search/6752?skillType=codemod) - -2. **Template Syntax Refactoring** - Refactor Jinja2 template syntax for better compatibility and readability. - [Run the Template Syntax Codemod](https://www.codegen.sh/search/6750?skillType=codemod) - -3. **Migration Feedback Enhancement** - Enhance feedback during the migration process for better tracking and debugging. - [Run the Migration Feedback Codemod](https://www.codegen.sh/search/6698?skillType=codemod) - -4. **Route Migration** - Migrate Flask routes to FastAPI's routing system. - [Run the Route Migration Codemod](https://www.codegen.sh/search/6699?skillType=codemod) - ---- - -## How to Migrate - -### Step 1: Migrate Static File Handling - -FastAPI uses a different approach for serving static files. Use the static file handling codemod to: - -- Update your static file serving logic to align with FastAPI's methods. - -👉 [Run the Static File Handling Codemod](https://www.codegen.sh/search/6752?skillType=codemod) - ---- - -### Step 2: Refactor Template Syntax - -Refactor your Jinja2 template syntax to ensure compatibility with FastAPI. This includes: - -- Updating template rendering logic. -- Ensuring all template syntax is compatible with FastAPI. - -👉 [Run the Template Syntax Codemod](https://www.codegen.sh/search/6750?skillType=codemod) - ---- - -### Step 3: Enhance Migration Feedback - -Improve the feedback you receive during the migration process. This helps in tracking progress and debugging issues. - -👉 [Run the Migration Feedback Codemod](https://www.codegen.sh/search/6698?skillType=codemod) - ---- - -### Step 4: Migrate Flask Routes - -FastAPI has a different routing system compared to Flask. Use the route migration codemod to: - -- Convert Flask routes to FastAPI routes. -- Ensure all route handlers are updated to FastAPI's syntax. - -👉 [Run the Route Migration Codemod](https://www.codegen.sh/search/6699?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 FastAPI migration today and enjoy the benefits of a cleaner, modern codebase! diff --git a/freezegun_to_timemachine_migration/run.py b/freezegun_to_timemachine_migration/run.py index da86ba3..b5e6bd1 100644 --- a/freezegun_to_timemachine_migration/run.py +++ b/freezegun_to_timemachine_migration/run.py @@ -1,42 +1,62 @@ +import codegen from codegen import Codebase -codebase = Codebase.from_repo("getmoto/moto", commit="786a8ada7ed0c7f9d8b04d49f24596865e4b7901") - -print("🚀 Starting FreezeGun to TimeMachine conversion...") - -for file in codebase.files: - if "tests" not in file.filepath: - continue - print(f"📝 Processing: {file.filepath}") - # Update imports - for imp in file.imports: - if imp.symbol_name and 'freezegun' in imp.source: - if imp.name == 'freeze_time': - # required due to Codegen limitations - imp.edit('from time_machine import travel') - else: - imp.set_import_module('time_machine') - # Find all function calls in the file - for fcall in file.function_calls: - # Skip if not a freeze_time call - if 'freeze_time' not in fcall.source: + + +@codegen.function("freezegun-to-timemachine") +def run(codebase: Codebase): + """Convert FreezeGun usage to TimeMachine in test files. + + This script: + 1. Identifies test files using FreezeGun. + 2. Updates imports from FreezeGun to TimeMachine. + 3. Modifies function calls to include necessary parameters. + """ + print("🚀 Starting FreezeGun to TimeMachine conversion...") + + for file in codebase.files: + if "tests" not in file.filepath: continue - # Get original source and prepare new source - new_source = fcall.source - # Add tick parameter if not present - if not fcall.get_arg_by_parameter_name('tick'): - if new_source.endswith(')'): - new_source = new_source[:-1] - if not new_source.endswith('('): - new_source += ',' - new_source += ' tick=False)' - # Replace freeze_time with travel - if '.' in new_source: - new_source = new_source.replace( - 'freeze_time', 'travel').replace('freezegun', 'time_machine') - else: - new_source = 'travel' + new_source[len('freeze_time'):] - # Make single edit with complete changes - fcall.edit(new_source) -codebase.commit() - -print("✅ FreezeGun to TimeMachine conversion completed successfully!") + print(f"📝 Processing: {file.filepath}") + + # Update imports + for imp in file.imports: + if imp.symbol_name and "freezegun" in imp.source: + if imp.name == "freeze_time": + # required due to Codegen limitations + imp.edit("from time_machine import travel") + else: + imp.set_import_module("time_machine") + + # Find all function calls in the file + for fcall in file.function_calls: + # Skip if not a freeze_time call + if "freeze_time" not in fcall.source: + continue + + # Get original source and prepare new source + new_source = fcall.source + + # Add tick parameter if not present + if not fcall.get_arg_by_parameter_name("tick"): + if new_source.endswith(")"): + new_source = new_source[:-1] + if not new_source.endswith("("): + new_source += "," + new_source += " tick=False)" + + # Replace freeze_time with travel + if "." in new_source: + new_source = new_source.replace("freeze_time", "travel").replace("freezegun", "time_machine") + else: + new_source = "travel" + new_source[len("freeze_time") :] + + # Make single edit with complete changes + fcall.edit(new_source) + + codebase.commit() + print("✅ FreezeGun to TimeMachine conversion completed successfully!") + + +if __name__ == "__main__": + codebase = Codebase.from_repo("getmoto/moto", commit="786a8ada7ed0c7f9d8b04d49f24596865e4b7901") + run(codebase) diff --git a/python2_to_python3/guide.md b/python2_to_python3/guide.md deleted file mode 100644 index 164bf09..0000000 --- a/python2_to_python3/guide.md +++ /dev/null @@ -1,39 +0,0 @@ -## How to Migrate - -### Step 1: Convert Print Statements to Function Calls - -Use the codemod to convert print statements in Python 2 to function calls in Python 3. - -👉 [Run the Convert Print Statements to Function Calls Codemod](https://www.codegen.sh/preview/7583) - -### Step 2: Unicode to Str Conversion - -Use the codemod to update Unicode string handling to be compatible with Python 3. - -👉 [Run the Unicode to Str Conversion Codemod](https://www.codegen.sh/preview/7587) - -### Step 3: Update Dictionary Iteration - -Use the codemod to update dictionary iteration to use the view objects returned by `dict.keys()`, `dict.values()`, and `dict.items()` in Python 3. - -👉 [Run the Update Dictionary Iteration Codemod](https://www.codegen.sh/preview/7590) - -### Step 4: Modernize Exception Handling - -Use the codemod to update exception handling syntax to be compatible with Python 3. - -👉 [Run the Modernize Exception Handling Codemod](https://www.codegen.sh/preview/7589) - -### Step 5: Update Iterators - -Use the codemod to replace the `next()` method with `__next__()` in iterators to be compatible with Python 3. - -👉 [Run the Update Iterators Codemod](https://www.codegen.sh/preview/7595) - ---- - -## 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 Python 3 migration today and enjoy the benefits of a cleaner, modern codebase! diff --git a/python2_to_python3/run.py b/python2_to_python3/run.py index 96ba108..1417c95 100644 --- a/python2_to_python3/run.py +++ b/python2_to_python3/run.py @@ -1,10 +1,10 @@ +import codegen from codegen import Codebase # Initialize codebase -codebase = Codebase("./") # Define the target directory -TARGET_DIR = "repo-before" +TARGET_DIR = "input_repo" def convert_print_statements(file): @@ -115,7 +115,8 @@ def update_iterators(file): stmt.edit(new_stmt) -def main(): +@codegen.function("python2-to-python3") +def run(): """Main function to run the Python 2 to 3 conversion""" print("🚀 Starting Python 2 to 3 conversion...\n") @@ -149,4 +150,6 @@ def main(): if __name__ == "__main__": - main() + codebase = Codebase("./") + + run(codebase) diff --git a/unittest_to_pytest/README.md b/unittest_to_pytest/README.md index a06b018..245fc78 100644 --- a/unittest_to_pytest/README.md +++ b/unittest_to_pytest/README.md @@ -1,12 +1,10 @@ -# unittest to pytest Migration Example +# Unittest to Pytest Migration Example -[![Documentation](https://img.shields.io/badge/docs-docs.codegen.com-blue)](https://docs.codegen.com/tutorials/unittest-to-pytest) +This codemod demonstrates how to automatically migrate `unittest` test suites to `pytest` using Codegen. The migration script simplifies the process by handling all the tedious manual updates automatically. -This example demonstrates how to use Codegen to automatically migrate unittest test suites to pytest. For a complete walkthrough, check out our [tutorial](https://docs.codegen.com/tutorials/unittest-to-pytest). +## How the Migration Script Works -## What This Example Does - -The migration script handles four key transformations: +The script automates the entire migration process in a few key steps: 1. **Convert Test Classes and Setup Methods** ```python @@ -29,6 +27,8 @@ The migration script handles four key transformations: user = db.create_user("test") assert user.name == "test" ``` + - Converts `unittest.TestCase` classes to standalone functions + - Replaces `setUp` methods with `pytest` fixtures 2. **Update Assertions** ```python @@ -45,6 +45,8 @@ The migration script handles four key transformations: with pytest.raises(ValueError): parse_id("invalid") ``` + - Replaces `unittest` assertions with `pytest` assertions + - Uses `pytest.raises` for exception testing 3. **Convert Test Discovery** ```python @@ -55,6 +57,8 @@ The migration script handles four key transformations: # To: # Remove unittest.main() and rename files to test_*.py ``` + - Removes `unittest.main()` calls + - Ensures files are named for `pytest` discovery 4. **Modernize Fixtures** ```python @@ -68,8 +72,9 @@ The migration script handles four key transformations: def conn(): return create_db() ``` + - Converts class-level setup to session-scoped fixtures -## Running the Example +## Running the Migration ```bash # Install Codegen @@ -84,7 +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 +- `repo-before/` - Sample `unittest` test suite to migrate - `guide.md` - Additional notes and explanations ## Learn More @@ -92,4 +97,8 @@ The script will process all Python test files in the `repo-before` directory and - [Full Tutorial](https://docs.codegen.com/tutorials/unittest-to-pytest) - [pytest Documentation](https://docs.pytest.org/) - [unittest Documentation](https://docs.python.org/3/library/unittest.html) -- [Codegen Documentation](https://docs.codegen.com) \ No newline at end of file +- [Codegen Documentation](https://docs.codegen.com) + +## Contributing + +Feel free to submit issues and enhancement requests! \ No newline at end of file diff --git a/unittest_to_pytest/guide.md b/unittest_to_pytest/guide.md deleted file mode 100644 index c683482..0000000 --- a/unittest_to_pytest/guide.md +++ /dev/null @@ -1,41 +0,0 @@ -# Guide: Migrating from Unittest to Pytest with Codegen - -This guide walks you through the steps to migrate your codebase from Unittest to Pytest using Codegen. Follow along to decouple your test cases from the Unittest framework and transform your setup methods into Pytest fixtures. Each step includes a direct link to the appropriate codemod for easy implementation. - ---- - -## 🎉 Overview of Changes - -The migration focuses on these key updates: - -1. **Remove Unittest Inheritance** - This codemod iterates through files in the tests directory and removes inheritance from `unittest.TestCase` for classes that have it. This helps in decoupling test cases from the Unittest framework, potentially preparing them for migration to another testing framework like Pytest. - [Run the Remove Unittest Inheritance Codemod](https://www.codegen.sh/preview/6867) - -2. **Transform setUp Methods to Pytest Fixtures** - This codemod transforms `setUp` methods in unit tests into Pytest fixtures, adding necessary imports and creating fixture functions. It updates test methods to utilize these fixtures, removes obsolete `setUp` methods, and eliminates Unittest imports, ensuring a seamless transition from Unittest to Pytest. - [Run the Transform setUp Methods Codemod](https://www.codegen.sh/preview/6919) - ---- - -## How to Migrate - -### Step 1: Remove Unittest Inheritance - -Use the codemod to remove inheritance from `unittest.TestCase` in your test classes. This will help decouple your test cases from the Unittest framework. - -👉 [Run the Remove Unittest Inheritance Codemod](https://www.codegen.sh/preview/6867) - -### Step 2: Transform setUp Methods to Pytest Fixtures - -Use the codemod to transform `setUp` methods into Pytest fixtures. This includes adding necessary imports, creating fixture functions, updating test methods to use these fixtures, and removing obsolete `setUp` methods and Unittest imports. - -👉 [Run the Transform setUp Methods Codemod](https://www.codegen.sh/preview/6919) - ---- - -## 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 Pytest migration today and enjoy the benefits of a cleaner, modern codebase! diff --git a/unittest_to_pytest/repo-after/jj_classes/__init__.py b/unittest_to_pytest/input_repo/jj_classes/__init__.py similarity index 100% rename from unittest_to_pytest/repo-after/jj_classes/__init__.py rename to unittest_to_pytest/input_repo/jj_classes/__init__.py diff --git a/unittest_to_pytest/repo-before/jj_classes/castle.py b/unittest_to_pytest/input_repo/jj_classes/castle.py similarity index 99% rename from unittest_to_pytest/repo-before/jj_classes/castle.py rename to unittest_to_pytest/input_repo/jj_classes/castle.py index cb95a69..7812ab3 100644 --- a/unittest_to_pytest/repo-before/jj_classes/castle.py +++ b/unittest_to_pytest/input_repo/jj_classes/castle.py @@ -1,5 +1,6 @@ # jj_classes/castle.py + class Castle: """Defines the Castle class.""" diff --git a/unittest_to_pytest/repo-after/jj_classes/character.py b/unittest_to_pytest/input_repo/jj_classes/character.py similarity index 99% rename from unittest_to_pytest/repo-after/jj_classes/character.py rename to unittest_to_pytest/input_repo/jj_classes/character.py index 53226be..30edf8b 100644 --- a/unittest_to_pytest/repo-after/jj_classes/character.py +++ b/unittest_to_pytest/input_repo/jj_classes/character.py @@ -1,5 +1,6 @@ # jj_classes/character.py + class Character: """Defines the Character class.""" diff --git a/unittest_to_pytest/repo-before/run_tests.py b/unittest_to_pytest/input_repo/run_tests.py similarity index 100% rename from unittest_to_pytest/repo-before/run_tests.py rename to unittest_to_pytest/input_repo/run_tests.py diff --git a/unittest_to_pytest/repo-before/jj_classes/__init__.py b/unittest_to_pytest/input_repo/tests/__init__.py similarity index 100% rename from unittest_to_pytest/repo-before/jj_classes/__init__.py rename to unittest_to_pytest/input_repo/tests/__init__.py diff --git a/unittest_to_pytest/repo-before/tests/test_classes.py b/unittest_to_pytest/input_repo/tests/test_classes.py similarity index 100% rename from unittest_to_pytest/repo-before/tests/test_classes.py rename to unittest_to_pytest/input_repo/tests/test_classes.py diff --git a/unittest_to_pytest/repo-after/jj_classes/castle.py b/unittest_to_pytest/repo-after/jj_classes/castle.py deleted file mode 100644 index cb95a69..0000000 --- a/unittest_to_pytest/repo-after/jj_classes/castle.py +++ /dev/null @@ -1,28 +0,0 @@ -# jj_classes/castle.py - -class Castle: - """Defines the Castle class.""" - - def __init__(self, name): - """Initialize the castle.""" - if not name: - raise ValueError("Castle name cannot be empty.") - self._name = name - self._boss = "Bowser" - self._world = "Grass Land" - - def has_access(self, character): - """Check if a character has access to the castle.""" - return character.powerup == "Super Mushroom" - - @property - def name(self): - return self._name - - @property - def boss(self): - return self._boss - - @property - def world(self): - return self._world diff --git a/unittest_to_pytest/repo-after/tests/__init__.py b/unittest_to_pytest/repo-after/tests/__init__.py deleted file mode 100644 index 5871ed8..0000000 --- a/unittest_to_pytest/repo-after/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -import pytest diff --git a/unittest_to_pytest/repo-after/tests/test_classes.py b/unittest_to_pytest/repo-after/tests/test_classes.py deleted file mode 100644 index 8de04e0..0000000 --- a/unittest_to_pytest/repo-after/tests/test_classes.py +++ /dev/null @@ -1,93 +0,0 @@ -# tests/test_classes.py - -import pytest -import unittest -from unittest.mock import Mock -from jj_classes.castle import Castle -from jj_classes.character import Character - - -class TestCastle(): - """Tests for the Castle class.""" - @pytest.fixture - def setup_testcastle(): - castle = Castle("Test Castle") - - - - def test_castle_name(setup_testcastle, Castle): - """Test that the castle name is set correctly.""" - assertEqual(castle.name, "Test Castle") - - def test_castle_boss(setup_testcastle, Castle): - """Test that the default boss is Bowser.""" - assertEqual(castle.boss, "Bowser") - - def test_castle_world(setup_testcastle, Castle): - """Test that the default world is Grass Land.""" - assertEqual(castle.world, "Grass Land") - - def test_has_access_granted(setup_testcastle, Castle): - """Test that access is granted for the correct powerup.""" - character = Mock(powerup="Super Mushroom") - assertTrue(castle.has_access(character)) - - def test_has_access_denied(setup_testcastle, Castle): - """Test that access is denied for an incorrect powerup.""" - character = Mock(powerup="Starman") - assertFalse(castle.has_access(character)) - - def test_empty_name_raises_error(setup_testcastle, Castle): - """Test that an empty castle name raises a ValueError.""" - with assertRaises(ValueError): - Castle("") - - -class TestCharacter(): - """Tests for the Character class.""" - @pytest.fixture - def setup_testcharacter(): - character = Character("Mario") - - - - def test_character_name(setup_testcharacter, Character): - """Test that the character name is set correctly.""" - assertEqual(character.name, "Mario") - - def test_default_powerup(setup_testcharacter, Character): - """Test that the default powerup is None.""" - assertIsNone(character.powerup) - - def test_set_powerup(setup_testcharacter, Character): - """Test setting a powerup.""" - character.powerup = "Fire Flower" - assertEqual(character.powerup, "Fire Flower") - - def test_empty_name_raises_error(setup_testcharacter, Character): - """Test that an empty character name raises a ValueError.""" - with assertRaises(ValueError): - Character("") - - -class TestCastleAndCharacter(unittest.TestCase): - """Tests for the interaction between Castle and Character.""" - @pytest.fixture - def setup_testcastleandcharacter(): - character = Character("Mario") - - - - def test_character_has_access(setup_testcastleandcharacter, Character): - """Test that a character with the correct powerup has access.""" - character.powerup = "Super Mushroom" - assertTrue(castle.has_access(character)) - - def test_character_denied_access(setup_testcastleandcharacter, Character): - """Test that a character with the wrong powerup is denied access.""" - character.powerup = "Starman" - assertFalse(castle.has_access(character)) - - -if __name__ == "__main__": - unittest.main() diff --git a/unittest_to_pytest/repo-before/jj_classes/character.py b/unittest_to_pytest/repo-before/jj_classes/character.py deleted file mode 100644 index 53226be..0000000 --- a/unittest_to_pytest/repo-before/jj_classes/character.py +++ /dev/null @@ -1,23 +0,0 @@ -# jj_classes/character.py - -class Character: - """Defines the Character class.""" - - def __init__(self, name): - """Initialize the character.""" - if not name: - raise ValueError("Character name cannot be empty.") - self._name = name - self._powerup = None - - @property - def name(self): - return self._name - - @property - def powerup(self): - return self._powerup - - @powerup.setter - def powerup(self, value): - self._powerup = value diff --git a/unittest_to_pytest/repo-before/tests/__init__.py b/unittest_to_pytest/repo-before/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/unittest_to_pytest/run.py b/unittest_to_pytest/run.py index b98ed61..b4e32a5 100644 --- a/unittest_to_pytest/run.py +++ b/unittest_to_pytest/run.py @@ -1,10 +1,10 @@ +import codegen from codegen import Codebase # Initialize codebase -codebase = Codebase("./") # Define the target directory -TARGET_DIR = "repo-before/tests" +TARGET_DIR = "input_repo/tests" def remove_unittest_inheritance(file): @@ -53,7 +53,8 @@ def {fixture_name}(): print(f"🗑️ Removed setUp method from class {cls.name}") -def main(): +@codegen.function("unittest-to-pytest") +def run(codebase: Codebase): """Main function to run the unittest to pytest conversion""" print("🚀 Starting unittest to pytest conversion...") @@ -76,4 +77,5 @@ def main(): if __name__ == "__main__": - main() + codebase = Codebase("./") + run(codebase)