Run pre-commit for the 1st time

OK, now this diff is very big, but it's actually modifying only style, not code functions themselves. From now on, this won't have to happen again.

Basically I just ran `pre-commit run --all-files` and committed that. I hope you like how it looks now!
This commit is contained in:
Jairo Llopis 2019-11-21 11:48:20 +00:00
parent 2ff11656e2
commit 0a952b7680
31 changed files with 218 additions and 226 deletions

View File

@ -10,7 +10,7 @@ cache:
matrix:
allow_failures:
- python: 'nightly'
- python: "nightly"
before_install:
- pip install -U pip coveralls

View File

@ -3,60 +3,60 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
### Version 3.0 (2019-xx)
- Dropped support for Python 3.5.
- Dropped support for deprecated `voodoo.json`.
- Type annotated entire code base.
- Dropped support for Python 3.5.
- Dropped support for deprecated `voodoo.json`.
- Type annotated entire code base.
### Version 2.5 (2019-06)
- Expanduser on all paths (so "~/foo/bar" is expanded to "<YOUR_HOME_FOLDER>/foo/bar").
- Improve the output when running tasks.
- Remove the destination folder if the copy process or one of the tasks fail.
- Add a `cleanup_on_error` flag to optionally disable the cleanup feature.
- Add the `skip_if_exists` option to skip files, without asking, if they already exists in the destination folder.
- Expanduser on all paths (so "~/foo/bar" is expanded to "<YOUR_HOME_FOLDER>/foo/bar").
- Improve the output when running tasks.
- Remove the destination folder if the copy process or one of the tasks fail.
- Add a `cleanup_on_error` flag to optionally disable the cleanup feature.
- Add the `skip_if_exists` option to skip files, without asking, if they already exists in the destination folder.
### Version 2.4.2 (2019-06)
- Fix MAJOR bug that was preventing the `_exclude`, `_include` and `_tasks` keys from
`copier.yml` (or alternatives) to be used at all. It also interpreted `_tasks` as
a user-provided variable.
- Fix MAJOR bug that was preventing the `_exclude`, `_include` and `_tasks` keys from
`copier.yml` (or alternatives) to be used at all. It also interpreted `_tasks` as
a user-provided variable.
### Version 2.4 (2019-06)
- Empty folders are now copied. The folders are also displayed in the console output
instead of just the files.
- `prompt_bool` can now have an undefined default (ans answer is mandatory in that case).
- Reactivates the `copier.yml` and `copier.yaml` as configuration files.
- The new `extra_paths` argument specifies additional paths to find templates to inherit from.
- Empty folders are now copied. The folders are also displayed in the console output
instead of just the files.
- `prompt_bool` can now have an undefined default (ans answer is mandatory in that case).
- Reactivates the `copier.yml` and `copier.yaml` as configuration files.
- The new `extra_paths` argument specifies additional paths to find templates to inherit from.
### Version 2.3 (2019-04)
- Back to using a setup.py intead of a pyproject.toml.
- The recommended configuration file is now `copier.toml`.
- Back to using a setup.py intead of a pyproject.toml.
- The recommended configuration file is now `copier.toml`.
### Version 2.2 (2019-04)
- The `copier` command-line script now accepts "help" and "version" as commands.
- The `copier` command-line script now accepts "help" and "version" as commands.
### Version 2.1 (2019-02)
- Task runner 🎉.
- Use `_exclude`, `_include`, and `_tasks` keys in `copier.yml` as the default
values for the `.copy()` arguments `exclude`, `include`, and `tasks`.
- Task runner 🎉.
- Use `_exclude`, `_include`, and `_tasks` keys in `copier.yml` as the default
values for the `.copy()` arguments `exclude`, `include`, and `tasks`.
### Version 2.0 (2019-02)
- Rebranded from `Voodoo` to `Copier`!
- Dropped support for Python 2.x, the minimal version is now Python 3.5.
- Cleanup and 100% test coverage.
- The recommended configuration file is now `copier.yaml`, but a `copier.json`
can be used as well. The old `voodoo.json` is also supported *for now* but is
deprecated and will be removed in version 2.2.
- Python package format updated to the latest standard (no `setup.py` 😵).
- Renamed the `render_skeleton()` function to `copy()`. The function signature remains
almost the same, the only changes are:
- `filter_this` parameter is now called `exclude`.
- `ignore_this` parameter is now called just `ignore`.
- Dropped the idea of storing the templates in a hidden `$HOME` folder.
- Rebranded from `Voodoo` to `Copier`!
- Dropped support for Python 2.x, the minimal version is now Python 3.5.
- Cleanup and 100% test coverage.
- The recommended configuration file is now `copier.yaml`, but a `copier.json`
can be used as well. The old `voodoo.json` is also supported _for now_ but is
deprecated and will be removed in version 2.2.
- Python package format updated to the latest standard (no `setup.py` 😵).
- Renamed the `render_skeleton()` function to `copy()`. The function signature remains
almost the same, the only changes are:
- `filter_this` parameter is now called `exclude`.
- `ignore_this` parameter is now called just `ignore`.
- Dropped the idea of storing the templates in a hidden `$HOME` folder.

View File

@ -55,7 +55,7 @@ Ready to contribute? Here's how to set up the project for local development.
git clone git@github.com:jpscaletti/copier.git
```
3. Install your local copy into a virtualenv.
3. Install your local copy into a virtualenv.
```bash
python -m virtualenv .venv
@ -79,7 +79,7 @@ flake8 .
```
To have multiple Python versions on the same machine for running `tox`, I recommend
using [pyenv](https://github.com/pyenv/pyenv) (*do not* confuse it with `pipenv`,).
using [pyenv](https://github.com/pyenv/pyenv) (_do not_ confuse it with `pipenv`,).
7. Commit your changes and push your branch to GitHub:
@ -91,7 +91,6 @@ git push origin name-of-your-bugfix-or-feature
8. Submit a pull request through the GitHub website.
## Pull Request Guidelines
Before you submit a pull request, check that it meets these guidelines:

174
README.md
View File

@ -6,15 +6,15 @@
A library for rendering projects templates.
- Works with **local** paths and **git URLs**.
- Your project can include any file and `Copier` can dynamically replace values in any kind of text files.
- It generates a beautiful output and takes care of not overwrite existing files unless instructed to do so.
- Works with **local** paths and **git URLs**.
- Your project can include any file and `Copier` can dynamically replace values in any kind of text files.
- It generates a beautiful output and takes care of not overwrite existing files unless instructed to do so.
![Sample output](https://github.com/pykong/copier/raw/master/copier-output.png)
## How to use
- Use it in your Python code:
- Use it in your Python code:
```python
from copier import copy
@ -32,7 +32,7 @@ copy("gh:pykong/copier.git", "path/to/destination")
copy("gl:pykong/copier.git", "path/to/destination")
```
- Or as a command-line tool:
- Or as a command-line tool:
```bash
copier path/to/project/template path/to/destination
@ -110,14 +110,14 @@ overwrite them.
```yaml
# Shell-style patterns files/folders that must not be copied.
_exclude:
- "*.bar"
- ".git"
- ".git/*"
- "*.bar"
- ".git"
- ".git/*"
# Shell-style patterns files/folders that *must be* copied, even if
# they are in the exclude list
_include:
- "foo.bar"
- "foo.bar"
# Shell-style patterns files to skip, without asking, if they already exists
# in the destination folder
@ -125,12 +125,12 @@ _skip_if_exists:
# Commands to be executed after the copy
_tasks:
- "git init"
- "rm [[ name_of_the_project ]]/README.md"
- "git init"
- "rm [[ name_of_the_project ]]/README.md"
# Additional paths, from where to search for templates
_extra_paths:
- ~/Projects/templates
- ~/Projects/templates
```
**Warning:** Use only trusted project templates as these tasks run with the
@ -151,7 +151,7 @@ this content:
```yml
# Changes here will be overwritten by Copier
[[ _log|to_nice_yaml ]]
[[_log|to_nice_yaml]]
```
The builtin `_log` variable includes all data needed to smooth future updates
@ -169,16 +169,16 @@ Copier includes:
### Builtin variables/functions
- `now()` to get current UTC time.
- `make_secret()` to get a random string.
- `now()` to get current UTC time.
- `make_secret()` to get a random string.
### Builtin filters
- `anything|to_nice_yaml` to print as pretty-formatted YAML.
- `anything|to_nice_yaml` to print as pretty-formatted YAML.
Without arguments it defaults to:
`anything|to_nice_yaml(indent=2, width=80, allow_unicode=True)`,
but you can modify those.
Without arguments it defaults to:
`anything|to_nice_yaml(indent=2, width=80, allow_unicode=True)`,
but you can modify those.
---
@ -213,89 +213,89 @@ Uses the template in _src_path_ to generate a new project at _dst_path_.
**Arguments**:
- **src_path** (str):<br>
Absolute path to the project skeleton. Can be a version control system URL.
- **src_path** (str):<br>
Absolute path to the project skeleton. Can be a version control system URL.
- **dst_path** (str):<br>
Absolute path to where to render the skeleton.
- **dst_path** (str):<br>
Absolute path to where to render the skeleton.
- **data** (dict):<br>
Data to be passed to the templates in addition to the user data from
a `copier.yml`.
- **data** (dict):<br>
Data to be passed to the templates in addition to the user data from
a `copier.yml`.
- **exclude** (list):<br>
A list of names or shell-style patterns matching files or folders
that must not be copied.
- **exclude** (list):<br>
A list of names or shell-style patterns matching files or folders
that must not be copied.
To exclude a folder you should use **two** entries, one for the folder and
the other for its content: `[".git", ".git/*"]`.
To exclude a folder you should use **two** entries, one for the folder and
the other for its content: `[".git", ".git/*"]`.
- **include** (list):<br>
A list of names or shell-style patterns matching files or folders that
must be included, even if its name is a match for the `exclude` list.
Eg: `['.gitignore']`. The default is an empty list.
- **include** (list):<br>
A list of names or shell-style patterns matching files or folders that
must be included, even if its name is a match for the `exclude` list.
Eg: `['.gitignore']`. The default is an empty list.
- **skip_if_exists** (list):<br>
Skip any of these files, without asking, if another with the same name already
exists in the destination folder. (it only makes sense if you are copying to a
folder that already exists).
- **skip_if_exists** (list):<br>
Skip any of these files, without asking, if another with the same name already
exists in the destination folder. (it only makes sense if you are copying to a
folder that already exists).
- **tasks** (list):<br>
Optional lists of commands to run in order after finishing the copy. Like in
the templates files, you can use variables on the commands that will be
replaced by the real values before running the command. If one of the commands
fails, the rest of them will not run.
- **tasks** (list):<br>
Optional lists of commands to run in order after finishing the copy. Like in
the templates files, you can use variables on the commands that will be
replaced by the real values before running the command. If one of the commands
fails, the rest of them will not run.
- **envops** (dict):<br>
Extra options for the Jinja template environment.
See available options in
[Jinja's docs](https://jinja.palletsprojects.com/en/2.10.x/api/#jinja2.Environment).
- **envops** (dict):<br>
Extra options for the Jinja template environment.
See available options in
[Jinja's docs](https://jinja.palletsprojects.com/en/2.10.x/api/#jinja2.Environment).
Copier uses these defaults that are different from Jinja's:
Copier uses these defaults that are different from Jinja's:
```yml
# copier.yml
_envops:
block_start_string: "[%"
block_end_string: "%]"
comment_start_string: "[#"
comment_end_string: "#]"
variable_start_string: "[["
variable_end_string: "]]"
keep_trailing_newline: true
```
```yml
# copier.yml
_envops:
block_start_string: "[%"
block_end_string: "%]"
comment_start_string: "[#"
comment_end_string: "#]"
variable_start_string: "[["
variable_end_string: "]]"
keep_trailing_newline: true
```
You can use default Jinja syntax with:
You can use default Jinja syntax with:
```yml
# copier.yml
_envops:
block_start_string: "{%"
block_end_string: "%}"
comment_start_string: "{#"
comment_end_string: "#}"
variable_start_string: "{{"
variable_end_string: "}}"
keep_trailing_newline: false
```
```yml
# copier.yml
_envops:
block_start_string: "{%"
block_end_string: "%}"
comment_start_string: "{#"
comment_end_string: "#}"
variable_start_string: "{{"
variable_end_string: "}}"
keep_trailing_newline: false
```
- **extra_paths** (list):<br>
Additional paths, from where to search for templates. This is intended to be
used with shared parent templates, files with macros, etc. outside the copied
project skeleton.
- **extra_paths** (list):<br>
Additional paths, from where to search for templates. This is intended to be
used with shared parent templates, files with macros, etc. outside the copied
project skeleton.
- **pretend** (bool):<br>
Run but do not make any changes.
- **pretend** (bool):<br>
Run but do not make any changes.
- **force** (bool):<br>
Overwrite files that already exist, without asking.
- **force** (bool):<br>
Overwrite files that already exist, without asking.
- **skip** (bool):<br>
Skip files that already exist, without asking.
- **skip** (bool):<br>
Skip files that already exist, without asking.
- **quiet** (bool):<br>
Suppress the status output.
- **quiet** (bool):<br>
Suppress the status output.
- **cleanup_on_error** (bool):<br>
Remove the destination folder if the copy process or one of the tasks fail.
True by default.
- **cleanup_on_error** (bool):<br>
Remove the destination folder if the copy process or one of the tasks fail.
True by default.

View File

@ -1,18 +1,22 @@
#!/usr/bin/env python
from plumbum import cli, colors
import sys
from .types import OptStr, AnyByStrDict
from plumbum import cli, colors
from .main import copy
from .types import AnyByStrDict, OptStr
from .version import __version__
class CopierApp(cli.Application):
DESCRIPTION = "Create a new project from a template."
DESCRIPTION_MORE = colors.yellow | """
DESCRIPTION_MORE = (
colors.yellow
| """
WARNING! Use only trusted project templates, as they might
execute code with the same level of access as your user.
"""
)
USAGE = """
copier [SWITCHES] [copy] template_src destination_path
copier [SWITCHES] [update] [destination_path]
@ -22,43 +26,46 @@ class CopierApp(cli.Application):
data: AnyByStrDict = {}
extra_paths = cli.SwitchAttr(
["-p", "--extra-paths"], str, list=True,
help="Additional directories to find parent templates in")
["-p", "--extra-paths"],
str,
list=True,
help="Additional directories to find parent templates in",
)
exclude = cli.SwitchAttr(
["-x", "--exclude"], str, list=True,
["-x", "--exclude"],
str,
list=True,
help=(
"A name or shell-style pattern matching files or folders "
"that must not be copied"
),
)
include = cli.SwitchAttr(
["-i", "--include"], str, list=True,
["-i", "--include"],
str,
list=True,
help=(
"A name or shell-style pattern matching files or folders "
"that must be included, even if their names are in the `exclude` list"
),
)
pretend = cli.Flag(
["-n", "--pretend"],
help="Run but do not make any changes",
)
pretend = cli.Flag(["-n", "--pretend"], help="Run but do not make any changes")
force = cli.Flag(
["-f", "--force"],
help="Overwrite files that already exist, without asking",
["-f", "--force"], help="Overwrite files that already exist, without asking"
)
skip = cli.Flag(
["-s", "--skip"],
help="Skip files that already exist, without asking",
)
quiet = cli.Flag(
["-q", "--quiet"],
help="Suppress status output",
["-s", "--skip"], help="Skip files that already exist, without asking"
)
quiet = cli.Flag(["-q", "--quiet"], help="Suppress status output")
@cli.switch(
["-d", "--data"], str, "VARIABLE=VALUE", list=True,
help="Make VARIABLE available as VALUE when rendering the template")
["-d", "--data"],
str,
"VARIABLE=VALUE",
list=True,
help="Make VARIABLE available as VALUE when rendering the template",
)
def data_switch(self, values):
self.data.update(value.split("=", 1) for value in values)
@ -83,12 +90,14 @@ class CopierApp(cli.Application):
if len(args) in {0, 1}:
self.nested_command = (
self._subcommands["update"].subapplication,
["copier update"] + list(args))
["copier update"] + list(args),
)
# If using 2 args, you want to copy
elif len(args) == 2:
self.nested_command = (
self._subcommands["copy"].subapplication,
["copier copy"] + list(args))
["copier copy"] + list(args),
)
# If using more args, you're wrong
else:
self.help()

View File

@ -52,14 +52,11 @@ def make_config(
raise NoSrcPathError(
"No .copier-answers.yml file found, or it didn't include "
"original template information (_src_path). "
"Run `copier copy` instead.",
"Run `copier copy` instead."
)
file_data = load_config_data(src_path, quiet=True)
config_data, query_data = filter_config(file_data)
query_data.update(filter(
lambda item: item[0] in query_data,
answers_data.items(),
))
query_data.update(filter(lambda item: item[0] in query_data, answers_data.items()))
if not force:
query_data = query_user_data(query_data)

View File

@ -6,7 +6,7 @@ from typing import Any, Tuple
from pydantic import BaseModel, Extra, StrictBool, validator
from ..types import AnyByStrDict, PathSeq, StrOrPathSeq, StrSeq, OptStr
from ..types import AnyByStrDict, OptStr, PathSeq, StrOrPathSeq, StrSeq
# Default list of files in the template to exclude from the rendered project
DEFAULT_EXCLUDE: Tuple[str, ...] = (
@ -39,7 +39,7 @@ class Flags(BaseModel):
skip: StrictBool = False
cleanup_on_error: StrictBool = True
@validator('skip', always=True)
@validator("skip", always=True)
def mutually_exclusive(cls, v, values):
if v and values["force"]:
raise ValueError(f"Flags `force` and `skip` are mutually exclusive.")

View File

@ -1,11 +1,11 @@
from pathlib import Path
from os.path import isfile
import re
from os.path import isfile
from pathlib import Path
from ..tools import HLINE, INDENT, printf_exception, prompt
from ..types import AnyByStrDict, StrOrPath, PathSeq
from ..types import AnyByStrDict, PathSeq, StrOrPath
__all__ = ("load_config_data", "query_user_data",)
__all__ = ("load_config_data", "query_user_data")
class ConfigFileError(ValueError):
@ -56,7 +56,8 @@ def load_config_data(
"""Try to load the content from a `copier.yml` or a `copier.yaml` file.
"""
conf_paths = [
p for p in Path(src_path).glob("copier.*")
p
for p in Path(src_path).glob("copier.*")
if p.is_file() and re.match(r"\.ya?ml", p.suffix, re.I)
]
@ -69,19 +70,21 @@ def load_config_data(
def load_logfile_data(
dst_path: StrOrPath,
*,
quiet: bool = False,
_warning: bool = True
dst_path: StrOrPath, *, quiet: bool = False, _warning: bool = True
) -> AnyByStrDict:
"""Load answers data from a `$dst_path/.copier-answers.yml` file if it exists.
`.yaml` suffix is also supported.
"""
answer_paths = list(filter(
isfile,
map(lambda suffix: Path(dst_path) / f".copier-answers.{suffix}", ("yml", "yaml")),
))
answer_paths = list(
filter(
isfile,
map(
lambda suffix: Path(dst_path) / f".copier-answers.{suffix}",
("yml", "yaml"),
),
)
)
answers_data: AnyByStrDict = {}
if len(answer_paths) > 1:
raise MultipleAnswerFilesError(answer_paths, quiet=quiet)
@ -90,7 +93,9 @@ def load_logfile_data(
return answers_data
def query_user_data(default_user_data: AnyByStrDict) -> AnyByStrDict: # pragma: no cover
def query_user_data(
default_user_data: AnyByStrDict
) -> AnyByStrDict: # pragma: no cover
"""Query to user about the data of the config file.
"""
if not default_user_data:

View File

@ -10,8 +10,8 @@ from . import vcs
from .config import make_config
from .config.objects import Flags
from .tools import (
Style,
Renderer,
Style,
copy_file,
get_jinja_renderer,
get_name_filters,

View File

@ -18,7 +18,6 @@ from .types import (
CheckPathFunc,
IntSeq,
JSONSerializable,
OptStrOrPathSeq,
OptBool,
OptStr,
StrOrPath,
@ -27,12 +26,7 @@ from .types import (
)
from .version import __version__
__all__ = (
"Style",
"printf",
"prompt",
"prompt_bool",
)
__all__ = ("Style", "printf", "prompt", "prompt_bool")
colorama.init()
@ -71,11 +65,7 @@ def printf(
def printf_exception(
e: Exception,
action: str,
msg: str = "",
indent: int = 0,
quiet: bool = False,
e: Exception, action: str, msg: str = "", indent: int = 0, quiet: bool = False
) -> None:
if not quiet:
print("")
@ -129,10 +119,7 @@ def prompt(
def prompt_bool(
question: str,
default: Optional[Any] = False,
yes: str = "y",
no: str = "n",
question: str, default: Optional[Any] = False, yes: str = "y", no: str = "n"
) -> OptBool:
please_answer = f' Please answer "{yes}" or "{no}"'
@ -187,7 +174,10 @@ def to_nice_yaml(data: Any, **kwargs) -> Optional[str]:
class Renderer:
def __init__(
self, env: SandboxedEnvironment, src_path: Path, data: AnyByStrDict,
self,
env: SandboxedEnvironment,
src_path: Path,
data: AnyByStrDict,
original_src_path: OptStr,
) -> None:
self.env = env
@ -198,7 +188,8 @@ class Renderer:
log["_src_path"] = original_src_path
# Other data goes next
log.update(
(k, v) for (k, v) in data.items()
(k, v)
for (k, v) in data.items()
if isinstance(k, JSONSerializable) and isinstance(v, JSONSerializable)
)
self.data = dict(data, _log=log)
@ -233,8 +224,9 @@ def get_jinja_renderer(
# Of couse we still have the post-copy tasks to worry about, but at least
# they are more visible to the final user.
env = SandboxedEnvironment(**envops)
return Renderer(env=env, src_path=src_path, data=data,
original_src_path=original_src_path)
return Renderer(
env=env, src_path=src_path, data=data, original_src_path=original_src_path
)
def normalize_str(text: StrOrPath, form: str = "NFD") -> str:

14
mm.py
View File

@ -27,18 +27,8 @@ data = {
"ruamel.yaml ~= 0.15",
"pydantic ~= 0.30",
],
"testing_requires": [
"pytest",
"pytest-mock",
"pytest-mypy"
"pytest-cov",
],
"development_requires": [
"pytest-flake8",
"flake8",
"ipdb",
"tox",
],
"testing_requires": ["pytest", "pytest-mock", "pytest-mypy" "pytest-cov"],
"development_requires": ["pytest-flake8", "flake8", "ipdb", "tox"],
"entry_points": "copier = copier.cli:run",
"coverage_omit": [],
}

View File

@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
combine_as_imports = true
force_grid_wrap = 0
include_trailing_comma = true
known_third_party = ["colorama", "jinja2", "pkg_resources", "pydantic", "pytest", "setuptools", "six"]
known_third_party = ["colorama", "jinja2", "pkg_resources", "plumbum", "pydantic", "pytest", "ruamel", "setuptools", "six"]
line_length = 88
multi_line_output = 3
use_parentheses = true

View File

@ -1 +1 @@
This file should be normally ignored
This file should be normally ignored

View File

@ -1 +1 @@
This is a triumph
This is a triumph

View File

@ -1 +1 @@
world
world

View File

@ -1 +1 @@
lorem ipsum
lorem ipsum

View File

@ -1,2 +1,2 @@
UTF-8ユーティーエフはち、ユーティーエフエイトはISO/IEC 10646(UCS)とUnicodeで使える8ビット符号単位の文字符号化形式及び文字符号化スキーム。
正式名称は、ISO/IEC 10646ではUCS Transformation Format 8、UnicodeではUnicode Transformation Format-8という。両者はISO/IEC 10646とUnicodeのコード重複範囲で互換性がある。RFCにも仕様がある[1]。
正式名称は、ISO/IEC 10646ではUCS Transformation Format 8、UnicodeではUnicode Transformation Format-8という。両者はISO/IEC 10646とUnicodeのコード重複範囲で互換性がある。RFCにも仕様がある[1]。

View File

@ -1,2 +1,2 @@
UTF-8ユーティーエフはち、ユーティーエフエイトはISO/IEC 10646(UCS)とUnicodeで使える8ビット符号単位の文字符号化形式及び文字符号化スキーム。
正式名称は、ISO/IEC 10646ではUCS Transformation Format 8、UnicodeではUnicode Transformation Format-8という。両者はISO/IEC 10646とUnicodeのコード重複範囲で互換性がある。RFCにも仕様がある[1]。
正式名称は、ISO/IEC 10646ではUCS Transformation Format 8、UnicodeではUnicode Transformation Format-8という。両者はISO/IEC 10646とUnicodeのコード重複範囲で互換性がある。RFCにも仕様がある[1]。

View File

@ -1,2 +1,2 @@
_tasks:
- exit 1
- exit 1

View File

@ -1,2 +1 @@
[% extends "parent.txt" %]

View File

@ -1,2 +1 @@
[% extends "parent.txt" %]

View File

@ -1 +1 @@
%343
%343

View File

@ -2,7 +2,7 @@
a_string: lorem ipsum
a_number: 12345
a_boolean: true
a_list:
a_list:
- one
- two
- three

View File

@ -1,4 +1,4 @@
A string: [[ a_string ]]
A number: [[ a_number ]]
A boolean: [[ a_boolean ]]
A list: [[ ", ".join(a_list) ]]
A list: [[ ", ".join(a_list) ]]

View File

@ -2,7 +2,7 @@
a_string: lorem ipsum
a_number: 12345
a_boolean: true
a_list:
a_list:
- one
- two
- three

View File

@ -1,4 +1,4 @@
A string: [[ a_string ]]
A number: [[ a_number ]]
A boolean: [[ a_boolean ]]
A list: [[ ", ".join(a_list) ]]
A list: [[ ", ".join(a_list) ]]

View File

@ -1,4 +1,4 @@
A string: lorem ipsum
A number: 12345
A boolean: True
A list: one, two, three
A list: one, two, three

View File

@ -36,8 +36,8 @@ GOOD_ENV_OPS = {
"variable_end_string": ">>",
"keep_trailing_newline": False,
"i_am_not_a_member": None,
'comment_end_string': '#>',
'comment_start_string': '<#',
"comment_end_string": "#>",
"comment_start_string": "<#",
}

View File

@ -1,9 +1,10 @@
import os
from pathlib import Path
import os
import pytest
import copier
from .helpers import DATA, PROJECT_TEMPLATE, assert_file, filecmp, render
@ -40,7 +41,9 @@ def test_copy(dst):
assert not os.path.exists(dst / "[% if py3 %]py3_only.py[% endif %]")
assert not os.path.exists(dst / "py2_only.py")
assert os.path.exists(dst / "py3_only.py")
assert not os.path.exists(dst / "[% if not py3 %]py2_folder[% endif %]" / "thing.py")
assert not os.path.exists(
dst / "[% if not py3 %]py2_folder[% endif %]" / "thing.py"
)
assert not os.path.exists(dst / "[% if py3 %]py3_folder[% endif %]" / "thing.py")
assert not os.path.exists(dst / "py2_folder" / "thing.py")
assert os.path.exists(dst / "py3_folder" / "thing.py")
@ -108,7 +111,6 @@ def test_config_exclude(dst, monkeypatch):
assert not (dst / "aaaa.txt").exists()
def test_config_exclude_overridden(dst):
def fake_data(*_args, **_kwargs):
return {"_exclude": ["*.txt"]}
@ -126,7 +128,6 @@ def test_config_include(dst, monkeypatch):
assert (dst / ".svn").exists()
def test_skip_option(dst):
render(dst)
path = dst / "pyproject.toml"

View File

@ -1,5 +1,6 @@
import copier
from copier.config.user_data import load_logfile_data
from .helpers import PROJECT_TEMPLATE
SRC = f"{PROJECT_TEMPLATE}_logfile"

View File

@ -6,5 +6,5 @@ from .helpers import PROJECT_TEMPLATE
def test_normal_jinja2(dst):
copier.copy(f"{PROJECT_TEMPLATE}_normal_jinja2", dst, force=True)
todo = (dst / "TODO.txt").read_text()
expected = '[[ Guybrush TODO LIST]]\n[# GROG #]\n - Become a pirate\n'
expected = "[[ Guybrush TODO LIST]]\n[# GROG #]\n - Become a pirate\n"
assert todo == expected