Skip to content

Commit

Permalink
[KED-2518] Fix starters for windows with python 3.7 (kedro-org#1070)
Browse files Browse the repository at this point in the history
  • Loading branch information
limdauto authored Apr 15, 2021
1 parent 84f0850 commit 0c117ae
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 16 deletions.
1 change: 1 addition & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ print(pipelines["__default__"]) # pipeline loading is only triggered here
* When `kedro new` is invoked using a configuration yaml file, `output_dir` is no longer a required key; by default the current working directory will be used.
* When `kedro new` is invoked using a configuration yaml file, the appropriate `prompts.yml` file is now used for validating the provided configuration. Previously, validation was always performed against the kedro project template `prompts.yml` file.
* When a relative path to a starter template is provided, `kedro new` now generates user prompts to obtain configuration rather than supplying empty configuration.
* Fixed error when using starter on Windows with Python 3.7 (Issue [#722](https://github.com/quantumblacklabs/kedro/issues/722))

## Minor breaking changes to the API

Expand Down
38 changes: 27 additions & 11 deletions kedro/framework/cli/starters.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@
This module implements commands available from the kedro CLI for creating
projects.
"""
import os
import re
import shutil
import stat
import tempfile
from collections import OrderedDict
from pathlib import Path
from typing import Any, Dict, List, Optional
from typing import Any, Callable, Dict, List, Optional, Tuple

import click
import git
Expand Down Expand Up @@ -80,6 +83,15 @@
)


# pylint: disable=unused-argument
def _remove_readonly(func: Callable, path: Path, excinfo: Tuple): # pragma: no cover
"""Remove readonly files on Windows
See: https://docs.python.org/3/library/shutil.html?highlight=shutil#rmtree-example
"""
os.chmod(path, stat.S_IWRITE)
func(path)


# pylint: disable=missing-function-docstring
@click.group(context_settings=CONTEXT_SETTINGS, name="Kedro")
def create_cli(): # pragma: no cover
Expand Down Expand Up @@ -121,16 +133,20 @@ def new(
template_path = str(TEMPLATE_PATH)

# Get prompts.yml to find what information the user needs to supply as config.
with tempfile.TemporaryDirectory() as tmpdir:
cookiecutter_dir = _get_cookiecutter_dir(
template_path, checkout, directory, tmpdir
)
prompts_required = _get_prompts_required(cookiecutter_dir)
# We only need to make cookiecutter_context if interactive prompts are needed.
if not config_path:
cookiecutter_context = _make_cookiecutter_context_for_prompts(
cookiecutter_dir
)

tmpdir = tempfile.mkdtemp()
cookiecutter_dir = _get_cookiecutter_dir(template_path, checkout, directory, tmpdir)
prompts_required = _get_prompts_required(cookiecutter_dir)
# We only need to make cookiecutter_context if interactive prompts are needed.
if not config_path:
cookiecutter_context = _make_cookiecutter_context_for_prompts(cookiecutter_dir)

# Cleanup the tmpdir after it's no longer required.
# Ideally we would want to be able to use tempfile.TemporaryDirectory() context manager
# but it causes an issue with readonly files on windows
# see: https://bugs.python.org/issue26660.
# So onerror, we will attempt to clear the readonly bits and re-attempt the cleanup
shutil.rmtree(tmpdir, onerror=_remove_readonly)

# Obtain config, either from a file or from interactive user prompts.
if not prompts_required:
Expand Down
6 changes: 1 addition & 5 deletions tests/framework/cli/test_starters.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,12 +362,8 @@ def test_new_with_invalid_starter_path_should_raise(self, fake_kedro_cli):
],
)
def test_new_with_starter_alias(
self, alias, expected_starter_repo, fake_kedro_cli, mocker, tmp_path
self, alias, expected_starter_repo, fake_kedro_cli, mocker
):
mocker.patch(
"kedro.framework.cli.starters.tempfile.TemporaryDirectory",
return_value=tmp_path,
)
mocked_cookie = mocker.patch("cookiecutter.main.cookiecutter")
CliRunner().invoke(
fake_kedro_cli,
Expand Down

0 comments on commit 0c117ae

Please sign in to comment.