Visual CLI improvements (#1032)

This commit is contained in:
Alek Petuskey 2023-05-16 20:42:53 -07:00 committed by GitHub
parent 6209916795
commit 4a580b54ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 172 additions and 16 deletions

View File

@ -4,7 +4,7 @@ branch = true
[report]
show_missing = true
fail_under = 80
fail_under = 79
precision = 2
# Regexes for lines to exclude from consideration

View File

@ -12,6 +12,8 @@ from typing import (
Optional,
)
from rich.progress import Progress
from pynecone import constants
from pynecone.config import get_config
from pynecone.utils import path_ops, prerequisites
@ -95,10 +97,38 @@ def export_app(
if deploy_url is not None:
generate_sitemap(deploy_url)
# Export the Next app.
subprocess.run(
[prerequisites.get_package_manager(), "run", "export"], cwd=constants.WEB_DIR
)
# Create a progress object
progress = Progress()
# Add a single task to the progress object
task = progress.add_task("Building app... ", total=500)
# Start the progress bar
with progress:
# Run the subprocess command
process = subprocess.Popen(
[prerequisites.get_package_manager(), "run", "export"],
cwd=constants.WEB_DIR,
stderr=subprocess.DEVNULL,
stdout=subprocess.PIPE, # Redirect stdout to a pipe
universal_newlines=True, # Set universal_newlines to True for text mode
)
# Read the output of the subprocess line by line
if process.stdout:
for line in iter(process.stdout.readline, ""):
# Update the progress bar based on the output
if "Linting and checking " in line:
progress.update(task, advance=100)
elif "Compiled successfully" in line:
progress.update(task, advance=100)
elif "Route (pages)" in line:
progress.update(task, advance=100)
elif "automatically rendered as static HTML" in line:
progress.update(task, advance=100)
elif "Export successful" in line:
progress.update(task, completed=500)
break # Exit the loop if the completion message is found
# Zip up the app.
if zip:

View File

@ -8,7 +8,9 @@ import subprocess
from pathlib import Path
from typing import TYPE_CHECKING
import typer
import uvicorn
from rich import print
from pynecone import constants
from pynecone.config import get_config
@ -30,6 +32,37 @@ def start_watching_assets_folder(root):
asset_watch.start()
def run_process_and_launch_url(run_command: list[str], root: Path):
"""Run the process and launch the URL.
Args:
run_command: The command to run.
root: root path of the project.
"""
process = subprocess.Popen(
run_command,
cwd=constants.WEB_DIR,
env=os.environ,
stderr=subprocess.DEVNULL,
stdout=subprocess.PIPE,
universal_newlines=True,
)
message_found = False
if process.stdout:
for line in process.stdout:
if "ready started server on" in line:
url = line.split("url: ")[-1].strip()
print(f"App running at: [bold green]{url}")
typer.launch(url)
message_found = True
break
if not message_found and process.stdout:
for line in process.stdout:
print(line, end="")
def run_frontend(app: App, root: Path, port: str):
"""Run the frontend.
@ -53,12 +86,8 @@ def run_frontend(app: App, root: Path, port: str):
# Run the frontend in development mode.
console.rule("[bold green]App Running")
os.environ["PORT"] = get_config().port if port is None else port
# Run the frontend in development mode.
subprocess.Popen(
[prerequisites.get_package_manager(), "run", "dev"],
cwd=constants.WEB_DIR,
env=os.environ,
run_process_and_launch_url(
[prerequisites.get_package_manager(), "run", "dev"], root
)
@ -80,10 +109,9 @@ def run_frontend_prod(app: App, root: Path, port: str):
os.environ["PORT"] = get_config().port if port is None else port
# Run the frontend in production mode.
subprocess.Popen(
[prerequisites.get_package_manager(), "run", "prod"],
cwd=constants.WEB_DIR,
env=os.environ,
console.rule("[bold green]App Running")
run_process_and_launch_url(
[prerequisites.get_package_manager(), "run", "prod"], root
)

View File

@ -4,8 +4,16 @@ from typing import Any
import pytest
import pynecone as pc
from pynecone.components.layout.box import Box
from pynecone.components.layout.cond import Cond, cond
from pynecone.components.layout.fragment import Fragment
from pynecone.components.layout.responsive import (
desktop_only,
mobile_and_tablet,
mobile_only,
tablet_and_desktop,
tablet_only,
)
from pynecone.components.typography.text import Text
from pynecone.vars import Var
@ -103,3 +111,33 @@ def test_cond_no_else():
# Props do not support the use of cond without else
with pytest.raises(ValueError):
cond(True, "hello")
def test_mobile_only():
"""Test the mobile_only responsive component."""
component = mobile_only("Content")
assert isinstance(component, Box)
def test_tablet_only():
"""Test the tablet_only responsive component."""
component = tablet_only("Content")
assert isinstance(component, Box)
def test_desktop_only():
"""Test the desktop_only responsive component."""
component = desktop_only("Content")
assert isinstance(component, Box)
def test_tablet_and_desktop():
"""Test the tablet_and_desktop responsive component."""
component = tablet_and_desktop("Content")
assert isinstance(component, Box)
def test_mobile_and_tablet():
"""Test the mobile_and_tablet responsive component."""
component = mobile_and_tablet("Content")
assert isinstance(component, Box)

View File

@ -2,7 +2,7 @@ from typing import Any, Dict, List
import pytest
from pynecone.components.tags import CondTag, Tag
from pynecone.components.tags import CondTag, Tag, tagless
from pynecone.event import EVENT_ARG, EventChain, EventHandler, EventSpec
from pynecone.vars import BaseVar, Var
@ -186,3 +186,10 @@ def test_format_cond_tag():
assert false_value["name"] == "h2"
assert false_value["contents"] == "False content"
def test_tagless_string_representation():
"""Test that the string representation of a tagless is correct."""
tag = tagless.Tagless(contents="Hello world")
expected_output = "Hello world"
assert str(tag) == expected_output

View File

@ -45,3 +45,56 @@ def test_json(child):
child: A child class.
"""
assert child.json().replace(" ", "") == '{"num":3.14,"key":"pi"}'
@pytest.fixture
def complex_child() -> Base:
"""A child class.
Returns:
A child class.
"""
class Child(Base):
num: float
key: str
name: str
age: int
active: bool
return Child(num=3.14, key="pi", name="John Doe", age=30, active=True)
def test_complex_get_fields(complex_child):
"""Test that the fields are set correctly.
Args:
complex_child: A child class.
"""
assert complex_child.get_fields().keys() == {"num", "key", "name", "age", "active"}
def test_complex_set(complex_child):
"""Test setting fields.
Args:
complex_child: A child class.
"""
complex_child.set(num=1, key="a", name="Jane Doe", age=28, active=False)
assert complex_child.num == 1
assert complex_child.key == "a"
assert complex_child.name == "Jane Doe"
assert complex_child.age == 28
assert complex_child.active is False
def test_complex_json(complex_child):
"""Test converting to json.
Args:
complex_child: A child class.
"""
assert (
complex_child.json().replace(" ", "")
== '{"num":3.14,"key":"pi","name":"JohnDoe","age":30,"active":true}'
)