Skip to content

Instantly share code, notes, and snippets.

@vzakharov
Last active September 2, 2023 11:37
Show Gist options
  • Save vzakharov/72ef9255c8cd455767f896c6719f36e5 to your computer and use it in GitHub Desktop.
Save vzakharov/72ef9255c8cd455767f896c6719f36e5 to your computer and use it in GitHub Desktop.
Python Relative Import Converter
# Relative Import Converter
#
# This Python script is used to convert absolute imports to relative imports in a Python project.
# It recursively traverses through all the Python files in the specified directory and its subdirectories.
# For each Python file, it identifies all the import statements and modifies them from absolute to relative.
# The script only converts imports from the current directory or its descendants, it does not handle
# imports from parent directories or unrelated directories (i.e., it doesn't do the `from ....../something` conversions).
# This is particularly useful when you want to make your Python modules/packages portable or when you are
# restructuring your project and need to update the import paths.
#
# Usage:
# Run the script from the command line with the directory path as argument.
# Example: python relative_import_converter.py <directory_path>
#
# Note: This script uses the `ast` module to parse the Python source code and the `re` module for string manipulation.
import os
import re
import ast
import argparse
import ast
def get_imports(source):
"""
Given a source code string, returns a generator that yields the names of all imported modules.
Args:
source (str): The source code string to parse.
Yields:
str: The name of an imported module.
"""
tree = ast.parse(source)
for node in tree.body:
if isinstance(node, ast.Import):
for alias in node.names:
yield alias.name
elif isinstance(node, ast.ImportFrom):
yield node.module
import re
def replace_imports(file_path, relative_path):
"""
Replaces imports in a Python file with relative imports.
Args:
file_path (str): The path to the Python file to modify.
relative_path (str): The relative path to the package containing the imports to replace.
Returns:
None
"""
with open(file_path, 'r') as file:
source = file.read()
imports = list(get_imports(source))
for import_name in imports:
if import_name.startswith(relative_path):
source = re.sub(r'from ' + import_name + ' import', 'from .' + import_name[len(relative_path)+1:] + ' import', source)
with open(file_path, 'w') as file:
file.write(source)
import os
def process_directory(path):
"""
Recursively walks through a directory and its subdirectories, finds all Python files, and replaces their imports with relative imports.
Args:
path (str): The path to the directory to process.
Returns:
None
"""
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith('.py'):
relative_path = os.path.relpath(root, path).replace(os.sep, '.')
replace_imports(os.path.join(root, file), relative_path)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Convert absolute imports to relative in a Python project.')
parser.add_argument('path', help='The directory path to process')
args = parser.parse_args()
process_directory(args.path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment