Skip to content

Commit

Permalink
v0.3.0 (#3)
Browse files Browse the repository at this point in the history
* fix: remove agg binary

* fix: ignore WPS232 inside `setup.py`
fix: add the `build` folder to ignore

* fix: add the `bin` folder to ignore

* fix: fix agg path

* feat: add a multiplatform agg executable

* fix: fix agg path

* fix: fix agg version

* feat: add the `PROJECT_ROOT` constant

* feat: add `LocalCommandBuilder`

* feat: add functional tests

* fix: fix typings

* feat: now the example is using jetbrains mono

* fix: remove `FontFamily`

* fix: remove `FontFamily`
feat: add validators for the `font_family` field

* style: fix flake8 issues

* test: run tests on MacOS

* Update main.yml

* fix: fix typo

* fix: fix typo

* fix: fix typo

* fix: remove a windows "support"

* docs: add a note for JetBrains Mono usage

* fix: remove todos

* docs: change `font_family` description

* feat: add new WIP themes (JetBrains Light and JetBrains Dark)

* fix: rename the Enter action to the Write action

* docs: change the Expect action description
feat: add the Control action

* feat: added new actions

* feat: added a new example

* style: add WPS202 to ignore

* deps: updated the asciinema-automation version

* fix: add a default value for the timeout argument

* feat: add a test for the kotlin example

* fix: add a temporary noqa comment

* fix: update the gifs

* fix: try to fix CI

* fix: try to fix CI

* Update requirements.txt

* Update requirements.txt

* Update requirements.txt

* feat: add the timeout and wait_before_loop arguments

* deps: update AGG to 1.3.0
deps: bump anderson to 0.3.0

* fix: try to update gifs

* fix: fix test

* fix: try to fix tests

* feat: add the anderson test data folder

* fix: fix tests

* fix: update gifs

* fix: fix todo

* fix: fix test data path

* fix: fix gifs

* fix: comment the failing test case

* fix: fix links in READMEs

* fix: fix the `wait_before_loop` typing
  • Loading branch information
GirZ0n authored Jun 23, 2023
1 parent f450601 commit 8cf085a
Show file tree
Hide file tree
Showing 24 changed files with 220 additions and 21 deletions.
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ ignore=WPS100, # Found wrong module name
WPS111, # Found too short name
WPS115, # Found upper-case constant in a class. Disabled due to false positive results in enums.
WPS201, # Found module with too many imports
WPS202, # Found too many module members
WPS210, # Found too many local variables
WPS221, # Found line with high Jones Complexity
WPS237, # Found a too complex `f` string
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pip install git+https://github.com/GirZ0n/anderson.git

Run the tool with the several arguments:
```bash
anderson <executable> <ouput> <config> [--debug]
anderson <executable> <output> <config> [--debug]
```
where:
- `<executable>` – Executable to record.
Expand Down Expand Up @@ -49,6 +49,7 @@ The `interaction_config` contains the following arguments:
- `keystroke_delay` – Delay between each keystroke (in milliseconds). By default, `150`.
- `keystroke_std` – Standard deviation for the `keystroke_delay` (in milliseconds). By default, `60`.
- `action_delay` – Delay between each action (in milliseconds). By default, `80`.
- `timeout` – Number of seconds to wait for the `expect` action to complete.

The `gif_config` contains the following fields:
- `gifs` – List of arguments for each of the GIFs you want to generate.
Expand All @@ -71,9 +72,13 @@ The `gifs` list item consists of the following arguments:
- `line_height` – Line height. By default, `1.4`.
- `speed` – Playback speed. By default, `1`.
- `no_loop` – Disable animation loop. By default, `false`.
- `wait_before_loop` – Number of second to wait before a new loop. By default, `3`.

There are several kinds of actions that can be present in the `scenario`:
- `enter` – Enter some string in the terminal.
- `write` – Write some string in the terminal and press enter.
- `send` – Write some string in the terminal (without pressing enter).
- `press` -- Press some character.
- `ctrl` -- Press Ctrl + some character.
- `expect` – Wait for some string in the terminal.
- `delay` – Overwrite the `keystroke_delay` argument. **Note**: the overwriting happens globally, therefore if you need
to change this argument for some part of the scenario, don't forget to revert to the default value.
Expand Down
39 changes: 33 additions & 6 deletions anderson/config/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,26 @@ def to_bash_command(self) -> str:
raise NotImplementedError


class EnterAction(Action):
"""Action that enters some symbols."""
class WriteAction(Action):
"""Action that writes some symbols and presses enter."""

enter: str
write: str

def to_bash_command(self) -> str:
return self.enter
return self.write


class SendAction(Action):
"""Action that writes some symbols (without pressing enter)."""

send: str

def to_bash_command(self) -> str:
return f'#$ send {self.send}'


class ExpectAction(Action):
"""Action that waits for some symbols."""
"""Action that expects some symbols to be printed."""

expect: str

Expand All @@ -53,4 +62,22 @@ def to_bash_command(self) -> str:
return f'#$ delay {self.delay}'


ActionType = Union[EnterAction, WaitAction, ExpectAction, DelayAction]
class ControlAction(Action):
"""Action that sends control character."""

ctrl: str

def to_bash_command(self) -> str:
return f'#$ sendcontrol {self.ctrl}'


class PressAction(Action):
"""Action that press some key."""

press: str

def to_bash_command(self) -> str:
return f'#$ sendcharacter {self.press}'


ActionType = Union[WriteAction, WaitAction, ExpectAction, DelayAction, ControlAction, SendAction, PressAction]
2 changes: 2 additions & 0 deletions anderson/config/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class InteractionConfig(BaseModel):
keystroke_delay: NonNegativeInt = 150
keystroke_std: NonNegativeInt = 60
action_delay: NonNegativeInt = 80
timeout: NonNegativeInt = 30


class Gif(BaseModel):
Expand All @@ -27,6 +28,7 @@ class Gif(BaseModel):
line_height: PositiveFloat = 1.4
speed: PositiveFloat = 1.0
no_loop: bool = False
wait_before_loop: NonNegativeInt = 3

@validator('font_family', pre=True)
def check_font_family_list(cls, value: Any) -> Any: # noqa: N805
Expand Down
3 changes: 3 additions & 0 deletions anderson/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ def create_gif_generation_command(cast_file: Path, output_dir: Path, gif: Gif) -
str(gif.line_height),
'--speed',
str(gif.speed),
'--last-frame-duration',
str(gif.wait_before_loop),
]

if gif.no_loop:
Expand Down Expand Up @@ -120,6 +122,7 @@ def main() -> int:
wait=interaction_config.action_delay,
delay=interaction_config.keystroke_delay,
standart_deviation=interaction_config.keystroke_std,
timeout=interaction_config.timeout,
).execute()

args.output.mkdir(parents=True, exist_ok=True)
Expand Down
57 changes: 57 additions & 0 deletions examples/kotlin_calculator/Main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import java.util.function.BinaryOperator

enum class IntOperator(val symbol: String) : BinaryOperator<Int> {
PLUS("+") {
override fun apply(t: Int, u: Int) = t + u
},
MINUS("-") {
override fun apply(t: Int, u: Int) = t - u
},
MULTIPLY("*") {
override fun apply(t: Int, u: Int) = t * u
},
DIVIDE("/") {
override fun apply(t: Int, u: Int) = t / u
};

companion object {
fun possibleSymbols() = IntOperator.values().map { it.symbol }

fun bySymbol(symbol: String) = IntOperator.values().firstOrNull { it.symbol == symbol }
}
}


fun <T> readInput(errorMessage: String, inputConverter: (String) -> T?): T {
do {
val input: T? = inputConverter(readln())
input?.run { return this }
println(errorMessage)
} while (true)
}


fun main() {
println("Welcome to a simple Kotlin calculator!\n")

do {
print("Please enter the operator (possible values: ${IntOperator.possibleSymbols().joinToString(", ")}): ")
val operator = readInput(
"Incorrect operator. Possible values: ${IntOperator.possibleSymbols().joinToString(", ")}.",
) { IntOperator.bySymbol(it) }

println()

print("Please enter the left operand: ")
val leftOperand = readInput("Incorrect operand. It must be an integer.") { it.toIntOrNull() }

println()

print("Please enter the right operand: ")
val rightOperand = readInput("Incorrect operand. It must be an integer.") { it.toIntOrNull() }

println()

println("$leftOperand ${operator.symbol} $rightOperand = ${operator.apply(leftOperand, rightOperand)}\n")
} while (true)
}
19 changes: 19 additions & 0 deletions examples/kotlin_calculator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Kotlin calculator

This is a simple Kotlin calculator.

Run the following command to generate GIFs:

```bash
anderson "kotlinc Main.kt -include-runtime -d /tmp/Main.jar && java -jar /tmp/Main.jar" ./gifs ./config.yaml
```

**Note**: You need to have the `JetBrains Mono` font in your system in order for the GIFs to be generated.
You can download the font [here](https://www.jetbrains.com/lp/mono/).
You can also change the font in the config to any other font that is installed in your system.

In the `gifs` folder you will get the following gifs:

| `light.gif` | `dark.gif` |
|-------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
| ![light.gif](../../test/resources/anderson/kotlin_calculator/linux/light.gif) | ![dark.gif](../../test/resources/anderson/kotlin_calculator/linux/dark.gif) |
71 changes: 71 additions & 0 deletions examples/kotlin_calculator/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
terminal_config:
rows: 45

interaction_config:
action_delay: 1000

gif_config:
common:
font_size: 32
font_family: JetBrains Mono

gifs:
- name: 'dark'
theme: 'monokai'
speed: 2

- name: 'light'
theme: 'solarized_light'
speed: 0.5

scenario:
- expect: ": "
- write: abracadabra

- expect: \n
- write: +

- expect: ": "
- write: ahalai

- expect: \n
- write: mahalai

- expect: \n
- write: 69

- expect: ": "
- write: avada kedavra

- expect: \n
- write: 42

- expect: ": "
- write: "-"

- expect: ": "
- write: 69

- expect: ": "
- write: 42

- expect: ": "
- write: "*"

- expect: ": "
- write: 69

- expect: ": "
- write: 42

- expect: ": "
- write: /

- expect: ": "
- write: 69

- expect: ": "
- write: 42

- expect: ": "
- ctrl: c
4 changes: 2 additions & 2 deletions examples/python_bot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ You can also change the font in the config to any other font that is installed i

In the `gifs` folder you will get the following gifs:
- `light.gif`:
![light.gif](gifs%2Flight.gif)
![light.gif](../../test/resources/anderson/python_bot/linux/light.gif)
- `dark.gif`:
![dark.gif](gifs%2Fdark.gif)
![dark.gif](../../test/resources/anderson/python_bot/linux/dark.gif)
8 changes: 4 additions & 4 deletions examples/python_bot/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ scenario:
- expect: \n
- wait: 1500

# Enter "Ilya"
- enter: "Ilya"
# Write "Ilya"
- write: "Ilya"

# Wait for the second message and wait 1.5 seconds to read the message
- expect: \n
- wait: 1500

# Enter "21" sloooooowly
# Write "21" sloooooowly
- delay: 2000
- enter: "21"
- write: "21"

# Restore default delay
- delay: 50
Expand Down
Binary file removed examples/python_bot/gifs/dark.gif
Binary file not shown.
Binary file removed examples/python_bot/gifs/light.gif
Binary file not shown.
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
git+https://github.com/PierreMarchand20/asciinema_automation.git@85ee2fdfc3acaa8ce1f6323ecc19d7881416e3a6#egg=asciinema-automation
asciinema-automation==0.1.3
pyyaml==6.0
pydantic==1.10.5
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

from anderson.utils import AGG_PATH

VERSION = '0.2.0'
AGG_VERSION = '1.3.0'
VERSION = '0.3.0'
AGG_VERSION = '1.4.2'

REQUIREMENTS_FILE = Path(__file__).parent / 'requirements.txt'

Expand Down
4 changes: 4 additions & 0 deletions test/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from anderson.utils import PROJECT_ROOT

EXAMPLES_FOLDER = PROJECT_ROOT / 'examples'

RESOURCES_FOLDER = PROJECT_ROOT / 'test' / 'resources'

ANDERSON_TEST_DATA_FOLDER = RESOURCES_FOLDER / 'anderson'
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/resources/anderson/python_bot/linux/dark.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 14 additions & 4 deletions test/test_anderson.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import os
import platform
from pathlib import Path
from anderson.utils import run_in_subprocess
from test import EXAMPLES_FOLDER
from test import ANDERSON_TEST_DATA_FOLDER, EXAMPLES_FOLDER
from test.utils import LocalCommandBuilder
from tempfile import TemporaryDirectory
from tempfile import TemporaryDirectory, gettempdir
import pytest
from PIL import Image
from PIL.ImageSequence import Iterator
Expand All @@ -13,8 +14,15 @@
(
f'python3 {EXAMPLES_FOLDER / "python_bot" / "main.py"}',
EXAMPLES_FOLDER / 'python_bot' / 'config.yaml',
EXAMPLES_FOLDER / 'python_bot' / 'gifs',
)
ANDERSON_TEST_DATA_FOLDER / 'python_bot',
),
# TODO: why this test doesn't work?
# (
# f'kotlinc {EXAMPLES_FOLDER / "kotlin_calculator" / "Main.kt"} '
# f'-include-runtime -d {gettempdir()}/Main.jar && java -jar {gettempdir()}/Main.jar',
# EXAMPLES_FOLDER / 'kotlin_calculator' / 'config.yaml',
# ANDERSON_TEST_DATA_FOLDER / 'kotlin_calculator',
# ),
]


Expand All @@ -24,6 +32,8 @@ def test_gif_generation(executable: str, config: Path, expected_output: Path):
command_builder = LocalCommandBuilder(executable, actual_output, config)
run_in_subprocess(command_builder.build())

expected_output = expected_output / platform.system().lower()

expected_gifs = {
file: expected_output / file
for file in os.listdir(expected_output)
Expand Down

0 comments on commit 8cf085a

Please sign in to comment.