Strategies¶
Strategies do the merging between the files from template and the target.
Strategies are specified in the scaraplate.yaml
file located in the root
of the template dir.
Sample scaraplate.yaml
excerpt:
default_strategy: scaraplate.strategies.Overwrite
strategies_mapping:
setup.py: scaraplate.strategies.TemplateHash
src/*/__init__.py: scaraplate.strategies.IfMissing
package.json:
strategy: mypackage.mymodule.MyPackageJson
config:
my_key: True
"src/{{ cookiecutter.myvariable }}.md": scaraplate.strategies.IfMissing
The strategy should be an importable Python class which implements
Strategy
.
default_strategy
and strategies_mapping
keys are the required ones.
The strategy value might be either a string (specifying a Python class),
or a dict of two keys – strategy
and config
. The first form
is just a shortcut for specifying a strategy with an empty config.
config
would be passed to the Strategy’s __init__
which would
be validated with the inner Schema
class.
-
class
scaraplate.strategies.
Strategy
¶ Bases:
abc.ABC
The abstract base class for a scaraplate Strategy.
To implement and use a custom strategy, the following needs to be done:
- Create a new Python class which implements
Strategy
- Override the inner
Schema
class if you need to configure your strategy fromscaraplate.yaml
. - Implement the
apply
method.
Assuming that the new strategy class is importable in the Python environment in which scaraplate is run, to use the strategy you need to specify it in
scaraplate.yaml
, e.g.strategies_mapping: myfile.txt: mypackage.mymodule.MyStrategy
-
class
Schema
¶ An empty default schema which doesn’t accept any parameters.
-
__init__
(*, target_contents: Optional[BinaryIO], template_contents: BinaryIO, template_meta: scaraplate.template.TemplateMeta, config: Dict[str, Any]) → None¶ Init the strategy.
Parameters: - target_contents – The file contents in the target project.
None
if the file doesn’t exist. - template_contents – The file contents from the template (after cookiecutter is applied).
- template_meta – Template metadata,
see
scaraplate.template.TemplateMeta
. - config – The strategy config from
scaraplate.yaml
. It is validated in this__init__
with the innerSchema
class.
- target_contents – The file contents in the target project.
-
apply
() → BinaryIO¶ Apply the Strategy.
Returns: The resulting file contents which would overwrite the target file.
- Create a new Python class which implements
Built-in Strategies¶
-
class
scaraplate.strategies.
Overwrite
¶ Bases:
scaraplate.strategies.Strategy
A simple strategy which always overwrites the target files with the ones from the template.
-
class
Schema
¶ An empty default schema which doesn’t accept any parameters.
-
class
-
class
scaraplate.strategies.
IfMissing
¶ Bases:
scaraplate.strategies.Strategy
A strategy which writes the file from the template only if it doesn’t exist in target.
-
class
Schema
¶ An empty default schema which doesn’t accept any parameters.
-
class
-
class
scaraplate.strategies.
SortedUniqueLines
¶ Bases:
scaraplate.strategies.Strategy
A strategy which combines both template and target files, sorts the combined lines and keeps only unique ones.
However, the comments in the beginning of the files are treated differently. They would be stripped from the target and replaced with the ones from the template. The most common usecase for this are the License headers.
Sample
scaraplate.yaml
excerpt:strategies_mapping: MANIFEST.in: strategy: scaraplate.strategies.SortedUniqueLines .gitignore: strategy: scaraplate.strategies.SortedUniqueLines
-
class
Schema
¶ Allowed params:
comment_pattern
[^ *([;#%]|//)
] – a PCRE pattern which should match the line with a comment.
-
class
-
class
scaraplate.strategies.
TemplateHash
¶ Bases:
scaraplate.strategies.Strategy
A strategy which appends to the target file a git commit hash of the template being applied; and the subsequent applications of the same template for this file are ignored until the HEAD commit of the template changes.
This strategy is useful when a file needs to be different from the template but there’s no suitable automated strategy yet, so it should be manually resynced on template updates.
This strategy overwrites the target file on each new commit in the template. There’s also a
RenderedTemplateFileHash
strategy which does it less frequently: only when the source file from the template has changes.Sample
scaraplate.yaml
excerpt:strategies_mapping: setup.py: strategy: scaraplate.strategies.TemplateHash config: line_comment_start: '#' max_line_length: 87 max_line_linter_ignore_mark: ' # noqa' Jenkinsfile: strategy: scaraplate.strategies.TemplateHash config: line_comment_start: '//'
This would result in the following:
setup.py:
...file contents... # Generated by https://github.com/rambler-digital-solutions/scaraplate # From https://github.com/rambler-digital-solutions/scaraplate-example-template/commit/1111111111111111111111111111111111111111 # noqa
Jenkinsfile:
...file contents... // Generated by https://github.com/rambler-digital-solutions/scaraplate // From https://github.com/rambler-digital-solutions/scaraplate-example-template/commit/1111111111111111111111111111111111111111
-
class
Schema
¶ Allowed params:
line_comment_start
[#
] – The prefix which should be used to start a line comment.max_line_length
[None] – The maximum line length for the appended line comments after which themax_line_linter_ignore_mark
suffix should be added.max_line_linter_ignore_mark
[# noqa
] – The linter’s line ignore mark for the appended line comments which are longer thanmax_line_length
columns. The default# noqa
mark silencesflake8
.
-
class
-
class
scaraplate.strategies.
RenderedTemplateFileHash
¶ Bases:
scaraplate.strategies.TemplateHash
A strategy which appends to the target file a hash of the rendered template file; and the subsequent applications of the same template for this file are ignored until the rendered file has changes.
This strategy is similar to
TemplateHash
with the difference that the target file is rewritten less frequently: only when the hash of the source file from the template is changed.New in version 0.2.
Sample
scaraplate.yaml
excerpt:strategies_mapping: setup.py: strategy: scaraplate.strategies.RenderedTemplateFileHash config: line_comment_start: '#' max_line_length: 87 max_line_linter_ignore_mark: ' # noqa' Jenkinsfile: strategy: scaraplate.strategies.RenderedTemplateFileHash config: line_comment_start: '//'
This would result in the following:
setup.py:
...file contents... # Generated by https://github.com/rambler-digital-solutions/scaraplate # RenderedTemplateFileHash d2671228e3dfc3e663bfaf9b5b151ce8 # From https://github.com/rambler-digital-solutions/scaraplate-example-template/commit/1111111111111111111111111111111111111111 # noqa
Jenkinsfile:
...file contents... // Generated by https://github.com/rambler-digital-solutions/scaraplate // RenderedTemplateFileHash d2as1228eb7233e663bfaf9b5b151ce8 // From https://github.com/rambler-digital-solutions/scaraplate-example-template/commit/1111111111111111111111111111111111111111
-
class
Schema
¶ Allowed params:
line_comment_start
[#
] – The prefix which should be used to start a line comment.max_line_length
[None] – The maximum line length for the appended line comments after which themax_line_linter_ignore_mark
suffix should be added.max_line_linter_ignore_mark
[# noqa
] – The linter’s line ignore mark for the appended line comments which are longer thanmax_line_length
columns. The default# noqa
mark silencesflake8
.
-
class
-
class
scaraplate.strategies.
ConfigParserMerge
¶ Bases:
scaraplate.strategies.Strategy
A strategy which merges INI-like files (with
configparser
).The resulting file is the one from the template with the following modifications:
- Comments are stripped
- INI file is reformatted (whitespaces are cleaned, sections and keys are sorted)
- Sections specified in the
preserve_sections
config list are preserved from the target file. - Keys specified in the
preserve_keys
config list are preserved from the target file.
This strategy cannot be used to merge config files which contain keys without a preceding section declaration (e.g.
.editorconfig
won’t work).Sample
scaraplate.yaml
excerpt:strategies_mapping: .pylintrc: strategy: scaraplate.strategies.ConfigParserMerge config: preserve_sections: [] preserve_keys: - sections: ^MASTER$ keys: ^extension-pkg-whitelist$ - sections: ^TYPECHECK$ keys: ^ignored- tox.ini: strategy: scaraplate.strategies.ConfigParserMerge config: preserve_sections: - sections: ^tox$ preserve_keys: - sections: ^testenv keys: ^extras$ pytest.ini: strategy: scaraplate.strategies.ConfigParserMerge config: preserve_sections: [] preserve_keys: - sections: ^pytest$ keys: ^python_files$ .isort.cfg: strategy: scaraplate.strategies.ConfigParserMerge config: preserve_sections: [] preserve_keys: - sections: ^settings$ keys: ^known_third_party$
-
class
Schema
¶ Allowed params:
preserve_keys
(required) – the list of config keys which should be preserved from the target file. Values schema:sections
(required) – a PCRE pattern matching sections containing the keys to preserve.keys
(required) – a PCRE pattern matching keys in the matched sections.
preserve_sections
(required) – the list of config sections which should be preserved from the target file. If the matching section exists in the template, it would be fully overwritten. Values schema:sections
(required) – a PCRE pattern matching sections which should be preserved from the target.excluded_keys
[None] – a PCRE pattern matching the keys which should not be overwritten in the template when preserving the section.
-
class
scaraplate.strategies.
SetupCfgMerge
¶ Bases:
scaraplate.strategies.ConfigParserMerge
A strategy which merges the Python’s
setup.cfg
file.Based on the
ConfigParserMerge
strategy, additionally containing amerge_requirements
config option for merging the lists of Python requirements between the files.Sample
scaraplate.yaml
excerpt:strategies_mapping: setup.cfg: strategy: scaraplate.strategies.SetupCfgMerge config: merge_requirements: - sections: ^options$ keys: ^install_requires$ - sections: ^options\.extras_require$ keys: ^develop$ preserve_keys: - sections: ^tool:pytest$ keys: ^testpaths$ - sections: ^build$ keys: ^executable$ preserve_sections: - sections: ^mypy- - sections: ^options\.data_files$ - sections: ^options\.entry_points$ - sections: ^options\.extras_require$
-
class
Schema
¶ Allowed params:
preserve_keys
(required) – the list of config keys which should be preserved from the target file. Values schema:sections
(required) – a PCRE pattern matching sections containing the keys to preserve.keys
(required) – a PCRE pattern matching keys in the matched sections.
preserve_sections
(required) – the list of config sections which should be preserved from the target file. If the matching section exists in the template, it would be fully overwritten. Values schema:sections
(required) – a PCRE pattern matching sections which should be preserved from the target.excluded_keys
[None] – a PCRE pattern matching the keys which should not be overwritten in the template when preserving the section.
merge_requirements
(required) – the list of config keys containing the lists of Python requirements which should be merged together. Values schema:sections
(required) – a PCRE pattern matching sections containing the keys with requirements.keys
(required) – a PCRE pattern matching keys in the matched sections.
-
class