-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
188 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,35 @@ | ||
""" | ||
CLI interface for generating blockchain test scripts. | ||
The `make` CLI streamlines the process of scaffolding tasks, such as generating new test files, | ||
enabling developers to concentrate on the core aspects of specification testing. | ||
It extracts a specified transaction and its required state from a blockchain network | ||
using the transaction hash and generates a Python test script based on that information. | ||
""" | ||
|
||
import os | ||
import jinja2 | ||
The module verifies the presence of a valid subcommand and calls the appropriate | ||
function for the subcommand. If an invalid subcommand is present, it throws an error | ||
and shows a list of valid subcommands. If no subcommand is present, it shows a list | ||
of valid subcommands to choose from. | ||
""" | ||
|
||
from cli.input import input_select, input_text | ||
import click | ||
|
||
template_loader = jinja2.PackageLoader("cli.make") | ||
template_env = jinja2.Environment(loader=template_loader, keep_trailing_newline=True) | ||
from cli.make.commands import test | ||
|
||
|
||
def test(): | ||
@click.group() | ||
def make(): | ||
""" | ||
Scaffold a test file from the command line interface (CLI). | ||
This function guides the user through a series of prompts to generate a test file | ||
for Ethereum execution specifications. The user is prompted to select the type of test, | ||
the fork to use, and to provide the EIP number and name. Based on the inputs, a test file | ||
is created in the appropriate directory with a rendered template. | ||
Prompts: | ||
- Choose the type of test to generate (State or Blockchain) | ||
- Select the fork to use (Prague or Osaka) | ||
- Enter the EIP number | ||
- Enter the EIP name | ||
The generated test file is saved in the following format: | ||
`tests/{fork}/{eip_number}_{eip_name}/test_{eip_name}.py` | ||
Example: | ||
If the user selects "State" as the test type, "Prague" as the fork, | ||
enters "1234" as the EIP number, | ||
and "Sample EIP" as the EIP name, the generated file will be: | ||
`tests/prague/1234_sample_eip/test_sample_eip.py` | ||
The function uses Jinja2 templates to render the content of the test file. | ||
Raises: | ||
- FileNotFoundError: If the template file does not exist. | ||
- IOError: If there is an error writing the file. | ||
The `make` CLI command helps you get started with new writing tests. | ||
""" | ||
test_type = input_select( | ||
"Choose the type of test to generate", choices=["State", "Blockchain"] | ||
) | ||
# TODO: Get forks from a config called `UPCOMING_FORKS` | ||
fork = input_select("Select the fork to use", choices=["Prague", "Osaka"]) | ||
pass | ||
|
||
eip_number = input_text("Enter the EIP number") | ||
|
||
# TODO: Perhaps get the EIP name from the number using an API? | ||
eip_name = input_text("Enter the EIP name") | ||
|
||
file_name = f"test_{eip_name.lower().replace(' ', '_')}.py" | ||
|
||
directory_path = f"tests/{fork.lower()}/{eip_number}-{eip_name.lower().replace(' ', '_')}" | ||
file_path = f"{directory_path}/{file_name}" | ||
|
||
# Create directories if they don't exist | ||
os.makedirs(directory_path, exist_ok=True) | ||
|
||
template = template_env.get_template(f"{test_type.lower()}_test.py.j2") | ||
rendered_template = template.render( | ||
fork=fork, | ||
eip_number=eip_number, | ||
eip_name=eip_name, | ||
test_name=eip_name.lower().replace(" ", "_"), | ||
) | ||
|
||
with open(file_path, "w") as file: | ||
file.write(rendered_template) | ||
|
||
print(f"Test file created at: {file_path}") | ||
""" | ||
################################ | ||
|| || | ||
|| Command Registration || | ||
|| || | ||
################################ | ||
Register nested commands here. For more information, see Click documentation: | ||
https://click.palletsprojects.com/en/8.0.x/commands/#nested-handling-and-contexts | ||
""" | ||
make.add_command(test) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
""" | ||
This subpackage holds subcommands for the make command. New subcommands must be created as | ||
modules and exported from this package, then registered under the make command in | ||
`cli.py`. | ||
""" | ||
|
||
from .test import test | ||
|
||
__all__ = ["test"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
""" | ||
This module contains a list of quotes related to system design. | ||
""" | ||
|
||
import random | ||
import textwrap | ||
|
||
make_something_great = [ | ||
"🎨 Simplicity is the ultimate sophistication. - Leonardo D.", | ||
"🖌️ Simplicity is an acquired taste. - Katharine G.", | ||
"💡 To create a memorable design you need to start with a thought that’s worth remembering." | ||
" - Thomas M.", | ||
"✏️ Designers are crazy and yet sane enough to know where to draw the line. - Benjamin W.", | ||
"🌟 Creativity is piercing the mundane to find the marvelous. - Bill M.", | ||
"🔍 Mistakes are the portals of discovery. - James J.", | ||
"🧠 It’s extremely difficult to be simultaneously concerned with the end-user experience of" | ||
" whatever it is that you’re building and the architecture of the program that delivers that" | ||
"experience. - James H.", | ||
"🧠 Good design is a lot like clear thinking made visual. - Edward T.", | ||
"🚀 Innovation leads one to see the new in the old and distinguishes the ingenious from the" | ||
" ingenuous. - Paul R.", | ||
"🔮 The best way to predict the future is to invent it. - Alan K.", | ||
"🌟 Perfection is achieved, not when there is nothing more to add, but when there is nothing" | ||
" left to take away. - Antoine d.", | ||
"📏 You can’t improve what you don’t measure. - Tom D.", | ||
] | ||
|
||
|
||
def wrap_quote(quote, width=80): | ||
""" | ||
Wraps the quote text to the given width. | ||
""" | ||
return textwrap.fill(quote, width=width) | ||
|
||
|
||
def box_quote(quote): | ||
""" | ||
Returns a quote wrapped in a box with borders. | ||
""" | ||
# Wrap the quote first | ||
wrapped_quote = wrap_quote(quote) | ||
|
||
# Calculate the width of the box | ||
box_width = max(len(line) for line in wrapped_quote.split("\n")) + 2 # +2 for side borders | ||
|
||
# Create top and bottom border | ||
top_bottom_border = "+" + "-" * (box_width) + "+" | ||
|
||
# Create the sides of the box | ||
lines = wrapped_quote.split("\n") | ||
boxed_lines = [f"{line.ljust(box_width - 2)}" for line in lines] | ||
|
||
# Return the full boxed quote | ||
quote = "\n".join([top_bottom_border] + boxed_lines + [top_bottom_border]) | ||
return f"\n {quote} \n" | ||
|
||
|
||
def get_quote(): | ||
""" | ||
Returns a random inspirational quote related to system design formatted in a box. | ||
""" | ||
return box_quote(random.choice(make_something_great)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
""" | ||
This module provides a CLI command to scaffold a test file. | ||
The `test` command guides the user through a series of prompts to generate a test file | ||
based on the selected test type, fork, EIP number, and EIP name. The generated test file | ||
is saved in the appropriate directory with a rendered template using Jinja2. | ||
""" | ||
|
||
import os | ||
|
||
import click | ||
import jinja2 | ||
|
||
from cli.input import input_select, input_text | ||
|
||
from .quotes import get_quote | ||
|
||
template_loader = jinja2.PackageLoader("cli.make") | ||
template_env = jinja2.Environment(loader=template_loader, keep_trailing_newline=True) | ||
|
||
|
||
@click.command() | ||
def test(): | ||
""" | ||
Create a new specification test file for an EIP. | ||
This function guides the user through a series of prompts to generate a test file | ||
for Ethereum execution specifications. The user is prompted to select the type of test, | ||
the fork to use, and to provide the EIP number and name. Based on the inputs, a test file | ||
is created in the appropriate directory with a rendered template. | ||
Prompts: | ||
- Choose the type of test to generate (State or Blockchain) | ||
- Select the fork to use (Prague or Osaka) | ||
- Enter the EIP number | ||
- Enter the EIP name | ||
The generated test file is saved in the following format: | ||
`tests/{fork}/eip{eip_number}_{eip_name}/test_{eip_name}.py` | ||
Example: | ||
If the user selects "State" as the test type, "Prague" as the fork, | ||
enters "1234" as the EIP number, | ||
and "Sample EIP" as the EIP name, the generated file will be: | ||
`tests/prague/eip1234_sample_eip/test_sample_eip.py` | ||
The function uses Jinja2 templates to render the content of the test file. | ||
Raises: | ||
- FileNotFoundError: If the template file does not exist. | ||
- IOError: If there is an error writing the file. | ||
""" | ||
test_type = input_select( | ||
"Choose the type of test to generate", choices=["State", "Blockchain"] | ||
) | ||
# TODO: Get forks from a config called `UPCOMING_FORKS` | ||
fork = input_select("Select the fork to use", choices=["Prague", "Osaka"]) | ||
|
||
eip_number = input_text("Enter the EIP number").strip() | ||
|
||
# TODO: Perhaps get the EIP name from the number using an API? | ||
eip_name = input_text("Enter the EIP name").strip() | ||
|
||
file_name = f"test_{eip_name.lower().replace(' ', '_')}.py" | ||
|
||
directory_path = f"tests/{fork.lower()}/eip{eip_number}_{eip_name.lower().replace(' ', '_')}" | ||
file_path = f"{directory_path}/{file_name}" | ||
|
||
# Create directories if they don't exist | ||
os.makedirs(directory_path, exist_ok=True) | ||
|
||
template = template_env.get_template(f"{test_type.lower()}_test.py.j2") | ||
rendered_template = template.render( | ||
fork=fork, | ||
eip_number=eip_number, | ||
eip_name=eip_name, | ||
test_name=eip_name.lower().replace(" ", "_"), | ||
) | ||
|
||
with open(file_path, "w") as file: | ||
file.write(rendered_template) | ||
|
||
print(f"\n 🎉 Success! Test file created at: {file_path}") | ||
print(get_quote()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters