jinja2-indent 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: jinja2-indent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Jinja2 extension for managing indentation in templates.
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Mihail Mishakin
|
|
7
|
+
Author-email: x896321475@gmail.com
|
|
8
|
+
Maintainer: Mihail Mishakin
|
|
9
|
+
Maintainer-email: x896321475@gmail.com
|
|
10
|
+
Requires-Python: >=3.9,<4.0
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Requires-Dist: jinja2 (>=3.0.0,<4.0.0)
|
|
23
|
+
Requires-Dist: jinja2-simple-tags (>=0.6.1,<0.7.0)
|
|
24
|
+
Project-URL: repository, https://github.com/dldevinc/jinja2-indent
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# jinja2-indent
|
|
28
|
+
|
|
29
|
+
This Jinja2 extension adjusts the indentation of block content to a specified width.
|
|
30
|
+
|
|
31
|
+
[](https://pypi.org/project/jinja2-indent/)
|
|
32
|
+
[](https://github.com/dldevinc/jinja2-indent)
|
|
33
|
+
[](https://pypi.org/project/jinja2-indent/)
|
|
34
|
+
|
|
35
|
+
## Compatibility
|
|
36
|
+
|
|
37
|
+
- `python` >= 3.9
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
Install the latest release with pip:
|
|
42
|
+
|
|
43
|
+
```shell
|
|
44
|
+
pip install jinja2-indent
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
The `{% indent %}` tag provided by this extension allows you to adjust the indentation level of the content inside the tag block. You can specify the desired width (in spaces), and the extension will reformat the content accordingly. This is particularly useful for aligning nested or indented structures in templates.
|
|
50
|
+
|
|
51
|
+
### Example
|
|
52
|
+
|
|
53
|
+
The following example demonstrates how to increase the indentation of a block of text:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from jinja2 import Environment
|
|
57
|
+
from jinja2_indent import IndentExtension
|
|
58
|
+
|
|
59
|
+
env = Environment(extensions=[IndentExtension])
|
|
60
|
+
|
|
61
|
+
template = env.from_string("""
|
|
62
|
+
root:
|
|
63
|
+
{% indent 4 %}
|
|
64
|
+
- name: a
|
|
65
|
+
value: 1
|
|
66
|
+
|
|
67
|
+
- name: b
|
|
68
|
+
value: 2
|
|
69
|
+
|
|
70
|
+
- name: c
|
|
71
|
+
value: 3
|
|
72
|
+
{% endindent %}
|
|
73
|
+
""")
|
|
74
|
+
|
|
75
|
+
output = template.render()
|
|
76
|
+
print(output)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
root:
|
|
81
|
+
- name: a
|
|
82
|
+
value: 1
|
|
83
|
+
|
|
84
|
+
- name: b
|
|
85
|
+
value: 2
|
|
86
|
+
|
|
87
|
+
- name: c
|
|
88
|
+
value: 3
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The following example demonstrates how to remove unnecessary indentation from a block of text:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from jinja2 import Environment
|
|
95
|
+
from jinja2_indent import IndentExtension
|
|
96
|
+
|
|
97
|
+
env = Environment(extensions=[IndentExtension])
|
|
98
|
+
|
|
99
|
+
template = env.from_string("""
|
|
100
|
+
- name: a
|
|
101
|
+
value: 1
|
|
102
|
+
|
|
103
|
+
{% indent 0 %}
|
|
104
|
+
- name: b
|
|
105
|
+
value: 2
|
|
106
|
+
{% endindent %}
|
|
107
|
+
|
|
108
|
+
- name: c
|
|
109
|
+
value: 3
|
|
110
|
+
""")
|
|
111
|
+
|
|
112
|
+
output = template.render()
|
|
113
|
+
print(output)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
- name: a
|
|
118
|
+
value: 1
|
|
119
|
+
|
|
120
|
+
- name: b
|
|
121
|
+
value: 2
|
|
122
|
+
|
|
123
|
+
- name: c
|
|
124
|
+
value: 3
|
|
125
|
+
```
|
|
126
|
+
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# jinja2-indent
|
|
2
|
+
|
|
3
|
+
This Jinja2 extension adjusts the indentation of block content to a specified width.
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/jinja2-indent/)
|
|
6
|
+
[](https://github.com/dldevinc/jinja2-indent)
|
|
7
|
+
[](https://pypi.org/project/jinja2-indent/)
|
|
8
|
+
|
|
9
|
+
## Compatibility
|
|
10
|
+
|
|
11
|
+
- `python` >= 3.9
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
Install the latest release with pip:
|
|
16
|
+
|
|
17
|
+
```shell
|
|
18
|
+
pip install jinja2-indent
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
The `{% indent %}` tag provided by this extension allows you to adjust the indentation level of the content inside the tag block. You can specify the desired width (in spaces), and the extension will reformat the content accordingly. This is particularly useful for aligning nested or indented structures in templates.
|
|
24
|
+
|
|
25
|
+
### Example
|
|
26
|
+
|
|
27
|
+
The following example demonstrates how to increase the indentation of a block of text:
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from jinja2 import Environment
|
|
31
|
+
from jinja2_indent import IndentExtension
|
|
32
|
+
|
|
33
|
+
env = Environment(extensions=[IndentExtension])
|
|
34
|
+
|
|
35
|
+
template = env.from_string("""
|
|
36
|
+
root:
|
|
37
|
+
{% indent 4 %}
|
|
38
|
+
- name: a
|
|
39
|
+
value: 1
|
|
40
|
+
|
|
41
|
+
- name: b
|
|
42
|
+
value: 2
|
|
43
|
+
|
|
44
|
+
- name: c
|
|
45
|
+
value: 3
|
|
46
|
+
{% endindent %}
|
|
47
|
+
""")
|
|
48
|
+
|
|
49
|
+
output = template.render()
|
|
50
|
+
print(output)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
root:
|
|
55
|
+
- name: a
|
|
56
|
+
value: 1
|
|
57
|
+
|
|
58
|
+
- name: b
|
|
59
|
+
value: 2
|
|
60
|
+
|
|
61
|
+
- name: c
|
|
62
|
+
value: 3
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The following example demonstrates how to remove unnecessary indentation from a block of text:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from jinja2 import Environment
|
|
69
|
+
from jinja2_indent import IndentExtension
|
|
70
|
+
|
|
71
|
+
env = Environment(extensions=[IndentExtension])
|
|
72
|
+
|
|
73
|
+
template = env.from_string("""
|
|
74
|
+
- name: a
|
|
75
|
+
value: 1
|
|
76
|
+
|
|
77
|
+
{% indent 0 %}
|
|
78
|
+
- name: b
|
|
79
|
+
value: 2
|
|
80
|
+
{% endindent %}
|
|
81
|
+
|
|
82
|
+
- name: c
|
|
83
|
+
value: 3
|
|
84
|
+
""")
|
|
85
|
+
|
|
86
|
+
output = template.render()
|
|
87
|
+
print(output)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
- name: a
|
|
92
|
+
value: 1
|
|
93
|
+
|
|
94
|
+
- name: b
|
|
95
|
+
value: 2
|
|
96
|
+
|
|
97
|
+
- name: c
|
|
98
|
+
value: 3
|
|
99
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .extension import IndentExtension
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import re
|
|
3
|
+
from typing import Generator
|
|
4
|
+
|
|
5
|
+
from jinja2_simple_tags import ContainerTag
|
|
6
|
+
|
|
7
|
+
re_initial_newline = re.compile(r"^\r?\n")
|
|
8
|
+
re_leading_spaces = re.compile(r"^([\s\t]*)(.*)")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class IndentExtension(ContainerTag):
|
|
12
|
+
"""
|
|
13
|
+
A Jinja2 extension for managing indentation in templates.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
tags = {"indent"}
|
|
17
|
+
|
|
18
|
+
def render(self, width: int, caller=None):
|
|
19
|
+
"""
|
|
20
|
+
Render the content with adjusted indentation.
|
|
21
|
+
|
|
22
|
+
Parameters:
|
|
23
|
+
- width (int): Target indentation width.
|
|
24
|
+
- caller (callable): A callable that provides the content to process.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
- str: The content with adjusted indentation.
|
|
28
|
+
"""
|
|
29
|
+
content = caller()
|
|
30
|
+
|
|
31
|
+
# Strip
|
|
32
|
+
content = re_initial_newline.sub("", content)
|
|
33
|
+
|
|
34
|
+
# Split lines and expand tabs to spaces
|
|
35
|
+
lines = split_and_expand_tabs(content)
|
|
36
|
+
|
|
37
|
+
# Get current indentation level
|
|
38
|
+
current_indentation = get_indentation(lines)
|
|
39
|
+
|
|
40
|
+
# Calculate the shift needed for the desired indentation
|
|
41
|
+
shift = max(-current_indentation, width - current_indentation)
|
|
42
|
+
|
|
43
|
+
# Adjust lines and join them back together
|
|
44
|
+
adjusted_lines = adjust_lines(lines, shift)
|
|
45
|
+
return "\n".join(adjusted_lines)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def split_and_expand_tabs(text: str, tabsize: int = 4) -> list[str]:
|
|
49
|
+
"""
|
|
50
|
+
Splits the given text into lines, preserving leading whitespace
|
|
51
|
+
and replacing tabs with spaces.
|
|
52
|
+
|
|
53
|
+
Parameters:
|
|
54
|
+
- text (str): The input text to be split into lines.
|
|
55
|
+
- tabsize (int, optional): The number of spaces to replace
|
|
56
|
+
each tab character with. Default is 4.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
- list[str]: A list of lines with tabs replaced by the specified number
|
|
60
|
+
of spaces, while maintaining the leading whitespace of each line.
|
|
61
|
+
"""
|
|
62
|
+
lines = []
|
|
63
|
+
for line in text.splitlines():
|
|
64
|
+
match = re_leading_spaces.match(line)
|
|
65
|
+
|
|
66
|
+
# Extract the leading whitespace characters (spaces and tabs)
|
|
67
|
+
leading_spaces = match.group(1)
|
|
68
|
+
|
|
69
|
+
# Extract the remaining content of the line
|
|
70
|
+
content = match.group(2)
|
|
71
|
+
|
|
72
|
+
# Replace all tabs with spaces, according to the specified tabsize
|
|
73
|
+
lines.append(leading_spaces.expandtabs(tabsize) + content)
|
|
74
|
+
|
|
75
|
+
return lines
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_indentation(lines: list[str]) -> int:
|
|
79
|
+
"""
|
|
80
|
+
Calculate the minimum indentation (number of leading spaces)
|
|
81
|
+
of non-whitespace lines in a list of strings.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
lines (list[str]): A list of strings to analyze for indentation.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
int: The minimum indentation of the non-whitespace lines.
|
|
88
|
+
Returns 0 if all lines are empty or contain only whitespace.
|
|
89
|
+
"""
|
|
90
|
+
if not lines:
|
|
91
|
+
return 0
|
|
92
|
+
|
|
93
|
+
indentation = float("inf")
|
|
94
|
+
|
|
95
|
+
for line in lines:
|
|
96
|
+
# Calculate the number of leading spaces in the current line
|
|
97
|
+
line_indentation = sum(1 for _ in itertools.takewhile(str.isspace, line))
|
|
98
|
+
|
|
99
|
+
# Skip whitespace-only lines
|
|
100
|
+
if line_indentation == len(line):
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
indentation = min(indentation, line_indentation)
|
|
104
|
+
|
|
105
|
+
return indentation if indentation != float("inf") else 0
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def adjust_lines(lines: list[str], shift: int) -> Generator[str, None, None]:
|
|
109
|
+
"""
|
|
110
|
+
Adjust the indentation of each line by adding or removing spaces.
|
|
111
|
+
|
|
112
|
+
Parameters:
|
|
113
|
+
- lines (list[str]): A list of strings to adjust.
|
|
114
|
+
- shift (int): The number of spaces to add (if positive) or remove (if negative).
|
|
115
|
+
|
|
116
|
+
Yields:
|
|
117
|
+
- str: The adjusted lines with modified indentation.
|
|
118
|
+
"""
|
|
119
|
+
if not lines:
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
if not shift:
|
|
123
|
+
yield from lines
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
for line in lines:
|
|
127
|
+
if not line:
|
|
128
|
+
yield line
|
|
129
|
+
elif shift > 0:
|
|
130
|
+
yield " " * shift + line
|
|
131
|
+
else:
|
|
132
|
+
yield line[-shift:]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "jinja2-indent"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A Jinja2 extension for managing indentation in templates."
|
|
5
|
+
authors = ["Mihail Mishakin <x896321475@gmail.com>"]
|
|
6
|
+
maintainers = ["Mihail Mishakin <x896321475@gmail.com>"]
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
license = "MIT"
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Operating System :: OS Independent",
|
|
11
|
+
"Development Status :: 3 - Alpha",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Programming Language :: Python",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
16
|
+
"Programming Language :: Python :: 3.9",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
]
|
|
22
|
+
packages = [
|
|
23
|
+
{ include = "jinja2_indent" },
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[tool.poetry.urls]
|
|
27
|
+
repository = "https://github.com/dldevinc/jinja2-indent"
|
|
28
|
+
|
|
29
|
+
[tool.poetry.dependencies]
|
|
30
|
+
python = "^3.9"
|
|
31
|
+
jinja2 = "^3.0.0"
|
|
32
|
+
jinja2-simple-tags = "^0.6.1"
|
|
33
|
+
|
|
34
|
+
[tool.poetry.group.pytest]
|
|
35
|
+
optional = true
|
|
36
|
+
|
|
37
|
+
[tool.poetry.group.pytest.dependencies]
|
|
38
|
+
pytest = "^8.3.4"
|
|
39
|
+
pytest-xdist = "^3.6.1"
|
|
40
|
+
pytest-cov = "*"
|
|
41
|
+
|
|
42
|
+
[tool.isort]
|
|
43
|
+
extend_skip = [".md", ".json"]
|
|
44
|
+
line_length = 90
|
|
45
|
+
known_first_party = ["jinja2_indent"]
|
|
46
|
+
multi_line_output = 5
|
|
47
|
+
|
|
48
|
+
[tool.flake8]
|
|
49
|
+
max-line-length = 90
|
|
50
|
+
extend-exclude = [
|
|
51
|
+
"tests",
|
|
52
|
+
]
|
|
53
|
+
per-file-ignores = [
|
|
54
|
+
"__init__.py: F401", # imported but unused
|
|
55
|
+
"apps.py: F401", # imported but unused
|
|
56
|
+
]
|
|
57
|
+
extend-ignore = [
|
|
58
|
+
# "E501", # line too long
|
|
59
|
+
"E128", # continuation line under-indented for visual indent
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
[tool.pytest.ini_options]
|
|
63
|
+
addopts = "--showlocals -rf -s"
|
|
64
|
+
norecursedirs = [
|
|
65
|
+
"*.egg",
|
|
66
|
+
".*",
|
|
67
|
+
"_darcs",
|
|
68
|
+
"build",
|
|
69
|
+
"CVS",
|
|
70
|
+
"dist",
|
|
71
|
+
"node_modules",
|
|
72
|
+
"venv",
|
|
73
|
+
".venv",
|
|
74
|
+
"{arch}",
|
|
75
|
+
"__pycache__",
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
[tool.coverage.run]
|
|
79
|
+
source = [
|
|
80
|
+
"jinja2_indent/",
|
|
81
|
+
]
|
|
82
|
+
omit = [
|
|
83
|
+
"*/tests/*",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
[build-system]
|
|
87
|
+
requires = ["poetry-core"]
|
|
88
|
+
build-backend = "poetry.core.masonry.api"
|