Skip to main content

Witchery

A Python Package for Code Analysis and Modification

Witchery is a powerful Python library that offers various functionalities for code analysis and modification. It provides tools to traverse Abstract Syntax Trees (AST) of Python code and perform tasks such as finding defined variables, removing specific variables, identifying local imports, adding function calls, and much more.

Whether you need to analyze code for missing variables, remove certain variables from your codebase, or perform code transformations, Witchery has you covered. It is a versatile utility for developers and programmers seeking to enhance their code analysis and modification capabilities.

With Witchery, you can easily parse Python code, identify used and defined variables, handle imports, and generate code for missing variables, among other useful features. This package is designed to simplify code manipulation tasks and assist in creating cleaner and more efficient Python codebases.

Features:

  • Find defined variables within Python code
  • Remove specific variables from code
  • Identify local imports in code
  • Remove imports of specific modules
  • Add function calls to existing code
  • Find missing variables in code
  • Generate ✨ magic ✨ code to define missing variables
  • and more!

PyPI - Version PyPI - Python Version
Code style: black License: MIT
su6 checks coverage.svg


Table of Contents

Installation

You can install witchery using pip:

pip install witchery

Usage

The witchery library provides several useful methods to work with Python code. Here are the main functions and their purposes:

  1. find_defined_variables(code_str: str) -> set[str]: Parses the given Python code and finds all variables that are defined within. It returns a set of variable names that are defined in the provided Python code.

  2. remove_specific_variables(code: str, to_remove: typing.Iterable[str] = ("db", "database")) -> str: Removes specific variables from the given code. You can specify a list of variable names to be removed, and the function will return the code after removing the specified variables.

  3. has_local_imports(code: str) -> bool: Checks if the given code has local imports. It returns True if local imports are found, and False otherwise.

  4. remove_import(code: str, module_name: typing.Optional[str]) -> str: Removes the import of a specific module from the given code. You can specify the name of the module to remove, and the function will return the code after removing the import of the specified module.

  5. remove_local_imports(code: str) -> str: Removes all local imports from the given code. It returns the code after removing all local imports.

  6. find_function_to_call(code: str, function_call_hint: str) -> typing.Optional[str]: Finds the function to call in the given code based on the function call hint. It returns the name of the function to call if found, or None otherwise.

  7. extract_function_details(function_call: str, default_args: typing.Iterable[str] = DEFAULT_ARGS) -> tuple[str | None, list[str]]: Extracts the function name and arguments from the function call string. It returns a tuple containing the function name and a list of arguments.

  8. add_function_call(code: str, function_call: str, args: typing.Iterable[str] = DEFAULT_ARGS) -> str: Adds a function call to the given code. You can specify the function call string and the arguments for the function call.

  9. find_variables(code_str: str) -> tuple[set[str], set[str]]: Finds all used and defined variables in the given code string. It returns a tuple containing sets of used and defined variables.

  10. find_missing_variables(code: str) -> set[str]: Finds and returns all missing variables in the given code. It returns a set of names of missing variables.

  11. generate_magic_code(missing_vars: set[str]) -> str: Generates code to define missing variables with a do-nothing object. After finding missing variables, it fills them in with an object that does nothing except return itself or an empty string.

Examples

import witchery

# Example 1: Find defined variables in code
code = """
x = 5
y = 10
z = x + y
"""
defined_vars = witchery.find_defined_variables(code)
print(defined_vars)
# Output: {'x', 'y', 'z'}

# Example 2: Remove specific variables from code
code = """
x = 5
y = 10
db = Database()
"""
new_code = witchery.remove_specific_variables(code, to_remove=["x", "db"])
print(new_code)
# Output: "y = 10"

# Example 3: Check if code has local imports
code = "from my_module import my_function"
has_local_imports = witchery.has_local_imports(code)
print(has_local_imports)
# Output: False

code = "from .my_module import my_function"
has_local_imports = witchery.has_local_imports(code)
print(has_local_imports)
# Output: True

# Example 4: Remove import of a specific module from code
code = """
import module_name
from module_name import something
x = module_name.function()
"""
new_code = witchery.remove_import(code, module_name="module_name")
print(new_code)
# Output: "x = module_name.function()"

# do note that this only removes the import, NOT any function calls to it!

# Example 5: Remove all local imports from code
code = """
from .local_module import something
from another_module import func

def my_function():
    return func(), something()
"""
new_code = witchery.remove_local_imports(code)
print(new_code)
# Output:
# from another_module import func
# 
# def my_function():
#     return func(), something()

# do note that this only removes the imports, NOT any function calls to it!

# Example 6: Find the function to call based on the function call hint
code = """
def my_function():
    return 42

x = my_function()
"""
function_to_call = witchery.find_function_to_call(code, "my_function()")  # can be with or without parentheses
print(function_to_call)
# Output: "my_function"

# will be None if the function does not exist in the specified code.

# Example 7: Extract function name and arguments from function call string
function_call = "my_function(x, y, 'z')"
function_name, args = witchery.extract_function_details(function_call)
print(function_name)
# Output: "my_function"
print(args)
# Output: ['x', 'y', "'z'"]

# Example 8: Add a function call to code
code = """
def add(a, b):
    return a + b

result = add(3, 5)
"""
new_code = witchery.add_function_call(code, function_call="add(x, y)")
print(new_code)
# Output: 
# def add(a, b):
#     return a + b
# add(x, y)
# result = add(3, 5)

# The call will be placed right below the function definition.

# Example 9: Find used and defined variables in code
code = """
x = 5
y = x + z
result = x * y
"""
used_vars, defined_vars = witchery.find_variables(code, with_builtins=False)
print(used_vars)
# Output: {'x', 'y', 'z'}
print(defined_vars)
# Output: {'x', 'y', 'result'}  # will be a lot longer if with_builtins = True

# Example 10: Find missing variables in code
code = """
x = 5
result = x * y
"""
missing_vars = witchery.find_missing_variables(code)
print(missing_vars)
# Output: {'y'}

# Example 11: Generate magic code to define missing variables
missing_vars = {'y', 'z'}
magic_code = witchery.generate_magic_code(missing_vars)
print(magic_code)
# Output: """
# class Empty:
#     ...
#
# empty = Empty()
# y = empty; z = empty;
# """

License

witchery is distributed under the terms of the MIT license.

Metadata

Release files for witchery 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for witchery 0.3.1
File Size Uploaded
witchery-0.3.1.tar.gz 13.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for witchery 0.3.1
File Interpreter ABI Platform
witchery-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 23.8 kB

Release files / witchery-0.3.1.tar.gz

Download URL witchery-0.3.1.tar.gz
Size 13.5 kB
Tags Source
SHA-256 checksum
How to use checksums
510f4cdafbfed34bae2638c8c03a9410576778415b26395f6e35aa8f36bd5650
BLAKE2b-256 checksum
How to use checksums
7f72369c255669edde76679db46adc3f13babcee65a2b167f9e7666712ea18f0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.7

Release files / witchery-0.3.1-py3-none-any.whl

Download URL witchery-0.3.1-py3-none-any.whl
Size 10.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d6e896a837a17ea5cc051c02ff164b77880b05c8254cc7cde51f06ceb0a89baf
BLAKE2b-256 checksum
How to use checksums
4be3784187d3961301a150805c9a291bfb7068ac2f36bca9e5cfef2de5c312ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.7

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page