Skip to content

Commit

Permalink
Add Python stubs as dependency and make lean init scaffold more
Browse files Browse the repository at this point in the history
  • Loading branch information
jmerle committed Feb 11, 2021
1 parent 3fb49cc commit baee269
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 65 deletions.
58 changes: 8 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,69 +28,27 @@ To debug backtests some additional setup is needed depending on the editor and l

### VS Code + Python
1. Install the [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) extension.
2. In your Lean CLI project, create the `.vscode/launch.json` file and add the following content:
```json5
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Remote Attach",
"type": "python",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${fileDirname}",
"remoteRoot": "/Project"
}
]
}
]
}
```
3. Run the `lean backtest` command with the `--debug vscode` option.
4. Wait until the CLI tells you to attach to the debugger.
5. In VS Code, open the Run tab and click on the green Run button in the top-left corner to attach to the debugger.
2. Run the `lean backtest` command with the `--debug mono` option.
3. Wait until the CLI tells you to attach to the debugger.
4. In VS Code, open the Run tab and run the configuration called "Debug Python with Lean CLI" (this configuration is created when you run `lean init`).

### VS Code + C#
TBD: Not working yet

1. Install version 15.8 of the [Mono Debug](https://marketplace.visualstudio.com/items?itemName=ms-vscode.mono-debug) extension. You can do this by first installing the latest version and then clicking on the arrow button next to the Uninstall button, which will open a context menu containing the "Install Another Version" option.
2. In your Lean CLI project, create the `.vscode/launch.json` file and add the following content:
```json5
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Mono",
"request": "attach",
"type": "mono",
"address": "localhost",
"port": 55555
}
]
}
```
3. Run the `lean backtest` command with the `--debug vscode` option.
4. Wait until the CLI tells you to attach to the debugger.
5. In VS Code, open the Run tab and click on the green Run button in the top-left corner to attach to the debugger.
2. Run the `lean backtest` command with the `--debug ptvsd` option.
3. Wait until the CLI tells you to attach to the debugger.
4. In VS Code, open the Run tab and run the configuration called "Debug C# with Lean CLI" (this configuration is created when you run `lean init`).

### PyCharm + Python
*Note: This combination requires PyCharm Professional.*

1. Create a new run configuration of type "Python Debug Server" with "IDE host name" set to "localhost", "Port" set to "6000" and add a path mapping where "Local path" is set to the absolute path to the directory containing your lean.json file and "Remote path" is set to "/LeanCLI".
2. Start the debugger in PyCharm using the run configuration from step 1.
3. Run the `lean backtest` command with the `--debug pycharm` option.
1. In PyCharm, start debugging using the "Debug with Lean CLI" run configuration (this configuration is created when you run `lean init`).
2. Run the `lean backtest` command with the `--debug pycharm` option.

### Visual Studio + C#
TBD

### Rider + C#
TBD

## Development

To work on the Lean CLI, clone the repository, enter an environment containing Python 3.6+ and run `pip install -r requirements.txt`. This command will install the required dependencies and installs the CLI in editable mode. This means you'll be able to edit the code and immediately see the results the next time you run `lean`.
Expand Down
10 changes: 6 additions & 4 deletions lean/commands/backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,15 @@ def backtest(project: Path, output: Optional[Path], update: bool, version: Optio
lean_runner.force_update()

# Detect the debugging method to use based on the editor and project language
debugging_method = None

if debug == "pycharm":
debug = "PyCharm"
debugging_method = "PyCharm"

if debug == "vs":
debug = "VisualStudio"
debugging_method = "VisualStudio"

if debug == "vscode":
debug = "PTVSD" if algorithm_file.name.endswith(".py") else "VisualStudio"
debugging_method = "PTVSD" if algorithm_file.name.endswith(".py") else "VisualStudio"

lean_runner.run_lean("backtesting", algorithm_file, output, version, debug)
lean_runner.run_lean("backtesting", algorithm_file, output, version, debugging_method)
81 changes: 81 additions & 0 deletions lean/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,74 @@
from lean.config import Config
from lean.container import container

CSPROJ = """
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.Lean" Version="2.4.10544" />
</ItemGroup>
</Project>
"""

IDEA_WORKSPACE_XML = """
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunManager" selected="Python Debug Server.Debug with Lean CLI">
<configuration name="Debug with Lean CLI" type="PyRemoteDebugConfigurationType" factoryName="Python Remote Debug">
<module name="LEAN" />
<option name="PORT" value="6000" />
<option name="HOST" value="localhost" />
<PathMappingSettings>
<option name="pathMappings">
<list>
<mapping local-root="$PROJECT_DIR$" remote-root="/LeanCLI" />
</list>
</option>
</PathMappingSettings>
<option name="REDIRECT_OUTPUT" value="true" />
<option name="SUSPEND_AFTER_CONNECT" value="true" />
<method v="2" />
</configuration>
<list>
<item itemvalue="Python Debug Server.Debug with Lean CLI" />
</list>
</component>
</project>
"""

VSCODE_LAUNCH_CONFIG = """
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Python with Lean CLI",
"type": "python",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${fileDirname}",
"remoteRoot": "/Project"
}
]
},
{
"name": "Debug C# with Lean CLI",
"request": "attach",
"type": "mono",
"address": "localhost",
"port": 55555
}
]
}
"""


@click.command(cls=LeanCommand)
def init() -> None:
Expand Down Expand Up @@ -60,6 +128,19 @@ def init() -> None:
with lean_config_path.open("w+") as file:
file.write(config)

# Create files which make debugging and autocompletion possible
extra_files = {
"LeanCLI.csproj": CSPROJ,
".idea/workspace.xml": IDEA_WORKSPACE_XML,
".vscode/launch.json": VSCODE_LAUNCH_CONFIG
}

for location, content in extra_files.items():
path = Path(Path.cwd() / location)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("w+") as file:
file.write(content)

# Prompt for some general configuration if not set yet
cli_config_manager = container.cli_config_manager()
if cli_config_manager.default_language.get_value() is None:
Expand Down
3 changes: 1 addition & 2 deletions lean/components/lean_config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,7 @@ def get_complete_lean_config(self,
This retrieves the path of the config, parses the file and adds all properties removed in clean_lean_config().
It is assumed that the default LEAN Docker image is used and that the project containing the algorithm_file
will be mounted in /Project.
It is assumed that the default LEAN Docker image is used and that the Lean CLI project is mounted at /LeanCLI.
:param environment: the environment to set
:param algorithm_file: the path to the algorithm that will be ran
Expand Down
2 changes: 2 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
filterwarnings = ignore::FutureWarning
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def get_version() -> str:
"jsoncomment~=0.4.2",
"docker~=4.4.1",
"rich~=9.10.0",
"dependency-injector~=4.20.1"
"dependency-injector~=4.20.1",
"quantconnect-stubs"
]

setup(
Expand Down
21 changes: 13 additions & 8 deletions tests/commands/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ def test_init_aborts_when_config_file_already_exists() -> None:
def test_init_aborts_when_data_directory_already_exists() -> None:
(Path.cwd() / "data").mkdir()

runner = CliRunner()
result = runner.invoke(lean, ["init"])
result = CliRunner().invoke(lean, ["init"])

assert result.exit_code != 0

Expand All @@ -64,17 +63,15 @@ def test_init_prompts_for_confirmation_when_directory_not_empty() -> None:


def test_init_prompts_for_default_language_when_not_set_yet() -> None:
runner = CliRunner()
result = runner.invoke(lean, ["init"], input="csharp\n")
result = CliRunner().invoke(lean, ["init"], input="csharp\n")

assert result.exit_code == 0

assert container.cli_config_manager().default_language.get_value() == "csharp"


def test_init_creates_data_directory_from_repo() -> None:
runner = CliRunner()
result = runner.invoke(lean, ["init"], input="csharp\n")
result = CliRunner().invoke(lean, ["init"], input="csharp\n")

assert result.exit_code == 0

Expand All @@ -86,8 +83,7 @@ def test_init_creates_data_directory_from_repo() -> None:


def test_init_creates_clean_config_file_from_repo() -> None:
runner = CliRunner()
result = runner.invoke(lean, ["init"], input="csharp\n")
result = CliRunner().invoke(lean, ["init"], input="csharp\n")

assert result.exit_code == 0

Expand All @@ -106,3 +102,12 @@ def test_init_creates_clean_config_file_from_repo() -> None:
"data-folder": "data"
}
""".strip()


@pytest.mark.parametrize("file", ["LeanCLI.csproj", ".idea/workspace.xml", ".vscode/launch.json"])
def test_init_creates_extra_files_supporting_autocompletion_and_debugging(file: str) -> None:
result = CliRunner().invoke(lean, ["init"], input="csharp\n")

assert result.exit_code == 0

assert (Path.cwd() / file).exists()

0 comments on commit baee269

Please sign in to comment.