Files
microsoft--promptflow/scripts/tool/generate_tool_package_template.py
T
wehub-resource-sync e768098d0e
Flake8 Lint / flake8 (push) Waiting to run
Spell check CI / Spell_Check (push) Waiting to run
tools_continuous_delivery / Private PyPI non-main branch release (push) Has been skipped
tools_continuous_delivery / Private PyPI main branch release (push) Failing after 2m42s
Publish Promptflow Doc / Build (push) Has been cancelled
Publish Promptflow Doc / Deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:39:52 +08:00

151 lines
5.8 KiB
Python

import argparse
import os
import re
from jinja2 import Environment, FileSystemLoader
def make_pythonic_variable_name(input_string):
variable_name = input_string.strip()
variable_name = re.sub(r'\W|^(?=\d)', '_', variable_name)
if not variable_name[0].isalpha() and variable_name[0] != '_':
variable_name = f'_{variable_name}'
return variable_name
def convert_tool_name_to_class_name(tool_name):
return ''.join(word.title() for word in tool_name.split('_'))
def create_file(path):
with open(path, 'w'):
pass
def create_folder(path):
os.makedirs(path, exist_ok=True)
def create_tool_project_structure(destination: str, package_name: str, tool_name: str,
function_name: str, is_class_way=False):
if is_class_way:
class_name = convert_tool_name_to_class_name(tool_name)
# Load templates
templates_abs_path = os.path.join(os.path.dirname(__file__), "templates")
file_loader = FileSystemLoader(templates_abs_path)
env = Environment(loader=file_loader)
# Create new directory
if os.path.exists(destination):
print("Destination already exists. Please choose another one.")
return
os.makedirs(destination, exist_ok=True)
# Generate setup.py
template = env.get_template('setup.py.j2')
output = template.render(package_name=package_name, tool_name=tool_name)
with open(os.path.join(destination, 'setup.py'), 'w') as f:
f.write(output)
# Generate MANIFEST.in
template = env.get_template('MANIFEST.in.j2')
output = template.render(package_name=package_name)
with open(os.path.join(destination, 'MANIFEST.in'), 'w') as f:
f.write(output)
# Create tools folder and __init__.py, tool.py inside it
tools_dir = os.path.join(destination, package_name, 'tools')
create_folder(tools_dir)
create_file(os.path.join(tools_dir, '__init__.py'))
with open(os.path.join(tools_dir, '__init__.py'), 'w') as f:
f.write('__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore\n')
# Generate tool.py
if is_class_way:
template = env.get_template('tool2.py.j2')
output = template.render(class_name=class_name, function_name=function_name)
else:
template = env.get_template('tool.py.j2')
output = template.render(function_name=function_name)
with open(os.path.join(tools_dir, f'{tool_name}.py'), 'w') as f:
f.write(output)
# Generate utils.py
template = env.get_template('utils.py.j2')
output = template.render()
with open(os.path.join(tools_dir, 'utils.py'), 'w') as f:
f.write(output)
create_file(os.path.join(destination, package_name, '__init__.py'))
with open(os.path.join(destination, package_name, '__init__.py'), 'w') as f:
f.write('__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore\n')
# Create yamls folder and __init__.py inside it
yamls_dir = os.path.join(destination, package_name, 'yamls')
create_folder(yamls_dir)
# Create tool yaml
if is_class_way:
template = env.get_template('tool2.yaml.j2')
output = template.render(package_name=package_name, tool_name=tool_name, class_name=class_name,
function_name=function_name)
else:
template = env.get_template('tool.yaml.j2')
output = template.render(package_name=package_name, tool_name=tool_name, function_name=function_name)
with open(os.path.join(yamls_dir, f'{tool_name}.yaml'), 'w') as f:
f.write(output)
# Create test folder and __init__.py inside it
tests_dir = os.path.join(destination, 'tests')
create_folder(tests_dir)
create_file(os.path.join(tests_dir, '__init__.py'))
# Create test_tool.py
if is_class_way:
template = env.get_template('test_tool2.py.j2')
output = template.render(package_name=package_name, tool_name=tool_name, class_name=class_name,
function_name=function_name)
else:
template = env.get_template('test_tool.py.j2')
output = template.render(package_name=package_name, tool_name=tool_name, function_name=function_name)
with open(os.path.join(tests_dir, f'test_{tool_name}.py'), 'w') as f:
f.write(output)
print(f'Generated tool package template for {package_name} at {destination}')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="promptflow tool template generation arguments.")
parser.add_argument("--package-name", "-p", type=str, help="your tool package's name", required=True)
parser.add_argument("--destination", "-d", type=str,
help="target folder you want to place the generated template", required=True)
parser.add_argument("--tool-name", "-t", type=str,
help="your tool's name, by default is hello_world_tool", required=False)
parser.add_argument("--function-name", "-f", type=str,
help="your tool's function name, by default is your tool's name", required=False)
parser.add_argument("--use-class", action='store_true', help="Specify whether to use a class implementation way.")
args = parser.parse_args()
destination = args.destination
package_name = make_pythonic_variable_name(args.package_name)
package_name = package_name.lower()
if args.tool_name:
tool_name = make_pythonic_variable_name(args.tool_name)
else:
tool_name = 'hello_world_tool'
tool_name = tool_name.lower()
if args.function_name:
function_name = make_pythonic_variable_name(args.function_name)
else:
function_name = tool_name
function_name = function_name.lower()
create_tool_project_structure(destination, package_name, tool_name, function_name, args.use_class)