Skip to content

Instantly share code, notes, and snippets.

@emoss08
Last active September 8, 2023 01:23
Show Gist options
  • Save emoss08/446e5f4b6536167a84cd57fc90288be9 to your computer and use it in GitHub Desktop.
Save emoss08/446e5f4b6536167a84cd57fc90288be9 to your computer and use it in GitHub Desktop.
Converts models.TextChoices to Typescript Const
"""
Converts Models.TextChoices to TypeScript Const.
Primarily used for Select Fields
Example:
Input:
class JobFunctionChoices(models.TextChoices):
MANAGER = "MANAGER", _("Manager")
MANAGEMENT_TRAINEE = "MANAGEMENT_TRAINEE", _("Management Trainee")
SUPERVISOR = "SUPERVISOR", _("Supervisor")
DISPATCHER = "DISPATCHER", _("Dispatcher")
BILLING = "BILLING", _("Billing")
FINANCE = "FINANCE", _("Finance")
SAFETY = "SAFETY", _("Safety")
SYS_ADMIN = "SYS_ADMIN", _("System Administrator")
TEST = "TEST", _("Test Job Function")
Output:
export const jobFunctionChoices = [
{ value: "MANAGER", label: "Manager" },
{ value: "MANAGEMENT_TRAINEE", label: "Management Trainee" },
{ value: "SUPERVISOR", label: "Supervisor" },
{ value: "DISPATCHER", label: "Dispatcher" },
{ value: "BILLING", label: "Billing" },
{ value: "FINANCE", label: "Finance" },
{ value: "SAFETY", label: "Safety" },
{ value: "SYS_ADMIN", label: "System Administrator" },
{ value: "TEST", label: "Test Job Function" },
];
"""
import ast
import os
from collections.abc import Generator
from typing import Any
def find_files(directory: str, extension: str) -> Generator[bytes | str, Any, None]:
"""Generate file paths that match a given extension in a directory.
This generator walks a directory tree, starting at `directory`, and yields
paths to files that have the specified `extension`.
Args:
directory (str): The root directory from which the search starts.
extension (str): The file extension to match.
Yields:
str: Full file path for each file that matches the given extension.
"""
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(extension):
yield os.path.join(root, file)
def find_and_convert_choices(directory: str) -> None:
"""Find Django TextChoices in Python files and print their TypeScript equivalent.
This function uses the `ast` module to parse Python source code and look for
Django TextChoices declarations. For each TextChoices found, it prints a TypeScript
equivalent.
Args:
directory (str): The root directory where the search for Python files starts.
Returns
None: This function does not return anything.
"""
for file in find_files(directory, ".py"):
with open(file) as f:
content = f.read()
try:
module = ast.parse(content)
except SyntaxError as e:
print(f"Skipping file {file} due to syntax error: {e}")
continue
for class_node in [
n for n in ast.walk(module) if isinstance(n, ast.ClassDef)
]:
for base in class_node.bases:
if isinstance(base, ast.Attribute) and base.attr == "TextChoices":
ts_conversion = []
for assign_node in [
n for n in ast.walk(class_node) if isinstance(n, ast.Assign)
]:
for _ in assign_node.targets:
if (
isinstance(assign_node.value, ast.Tuple)
and len(assign_node.value.elts) == 2
):
value = assign_node.value.elts[0].s
label = assign_node.value.elts[1].args[0].s
ts_conversion.append(
f' {{ value: "{value}", label: "{label}" }},'
)
ts_string = (
f"export const {class_node.name[0].lower() + class_node.name[1:]} = [\n"
+ "\n".join(ts_conversion)
+ "\n];"
)
print(ts_string)
f.close()
find_and_convert_choices("../billing")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment