Skip to content

Commit ee4d163

Browse files
Allow only non-empty brackets/braces
We'd like to disallow brackets and braces in our YAML, but there's a catch: the only way to describe an empty array or hash in YAML is to supply an empty one (`[]` or `{}`). Otherwise, the value will be null. This commit adds a `non-empty` option to `forbid` for brackets and braces. When it is set, all flow and sequence mappings will cause errors _except_ for empty ones.
1 parent 22335b2 commit ee4d163

File tree

4 files changed

+95
-6
lines changed

4 files changed

+95
-6
lines changed

tests/rules/test_braces.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,30 @@ def test_forbid(self):
6161
' a: 1\n'
6262
'}\n', conf, problem=(2, 8))
6363

64+
conf = ('braces:\n'
65+
' forbid: non-empty\n')
66+
self.check('---\n'
67+
'dict:\n'
68+
' a: 1\n', conf)
69+
self.check('---\n'
70+
'dict: {}\n', conf)
71+
self.check('---\n'
72+
'dict: {\n'
73+
'}\n', conf)
74+
self.check('---\n'
75+
'dict: {\n'
76+
'# commented: value\n'
77+
'# another: value2\n'
78+
'}\n', conf)
79+
self.check('---\n'
80+
'dict: {a}\n', conf, problem=(2, 8))
81+
self.check('---\n'
82+
'dict: {a: 1}\n', conf, problem=(2, 8))
83+
self.check('---\n'
84+
'dict: {\n'
85+
' a: 1\n'
86+
'}\n', conf, problem=(2, 8))
87+
6488
def test_min_spaces(self):
6589
conf = ('braces:\n'
6690
' max-spaces-inside: -1\n'

tests/rules/test_brackets.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,29 @@ def test_forbid(self):
6060
' b\n'
6161
']\n', conf, problem=(2, 9))
6262

63+
conf = ('brackets:\n'
64+
' forbid: non-empty\n')
65+
self.check('---\n'
66+
'array:\n'
67+
' - a\n'
68+
' - b\n', conf)
69+
self.check('---\n'
70+
'array: []\n', conf)
71+
self.check('---\n'
72+
'array: [\n\n'
73+
']\n', conf)
74+
self.check('---\n'
75+
'array: [\n'
76+
'# a comment\n'
77+
']\n', conf)
78+
self.check('---\n'
79+
'array: [a, b]\n', conf, problem=(2, 9))
80+
self.check('---\n'
81+
'array: [\n'
82+
' a,\n'
83+
' b\n'
84+
']\n', conf, problem=(2, 9))
85+
6386
def test_min_spaces(self):
6487
conf = ('brackets:\n'
6588
' max-spaces-inside: -1\n'

yamllint/rules/braces.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
2323
* ``forbid`` is used to forbid the use of flow mappings which are denoted by
2424
surrounding braces (``{`` and ``}``). Use ``true`` to forbid the use of flow
25-
mappings completely.
25+
mappings completely. Use ``non-empty`` to forbid the use of all flow
26+
mappings except for empty ones.
2627
* ``min-spaces-inside`` defines the minimal number of spaces required inside
2728
braces.
2829
* ``max-spaces-inside`` defines the maximal number of spaces allowed inside
@@ -60,6 +61,18 @@
6061
6162
object: { key1: 4, key2: 8 }
6263
64+
#. With ``braces: {forbid: non-empty}``
65+
66+
the following code snippet would **PASS**:
67+
::
68+
69+
object: {}
70+
71+
the following code snippet would **FAIL**:
72+
::
73+
74+
object: { key1: 4, key2: 8 }
75+
6376
#. With ``braces: {min-spaces-inside: 0, max-spaces-inside: 0}``
6477
6578
the following code snippet would **PASS**:
@@ -128,7 +141,7 @@
128141

129142
ID = 'braces'
130143
TYPE = 'token'
131-
CONF = {'forbid': bool,
144+
CONF = {'forbid': (bool, 'non-empty'),
132145
'min-spaces-inside': int,
133146
'max-spaces-inside': int,
134147
'min-spaces-inside-empty': int,
@@ -141,7 +154,15 @@
141154

142155

143156
def check(conf, token, prev, next, nextnext, context):
144-
if conf['forbid'] and isinstance(token, yaml.FlowMappingStartToken):
157+
if (conf['forbid'] is True and
158+
isinstance(token, yaml.FlowMappingStartToken)):
159+
yield LintProblem(token.start_mark.line + 1,
160+
token.end_mark.column + 1,
161+
'forbidden flow mapping')
162+
163+
elif (conf['forbid'] == 'non-empty' and
164+
isinstance(token, yaml.FlowMappingStartToken) and
165+
not isinstance(next, yaml.FlowMappingEndToken)):
145166
yield LintProblem(token.start_mark.line + 1,
146167
token.end_mark.column + 1,
147168
'forbidden flow mapping')

yamllint/rules/brackets.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
2323
* ``forbid`` is used to forbid the use of flow sequences which are denoted by
2424
surrounding brackets (``[`` and ``]``). Use ``true`` to forbid the use of
25-
flow sequences completely.
25+
flow sequences completely. Use ``non-empty`` to forbid the use of all flow
26+
sequences except for empty ones.
2627
* ``min-spaces-inside`` defines the minimal number of spaces required inside
2728
brackets.
2829
* ``max-spaces-inside`` defines the maximal number of spaces allowed inside
@@ -61,6 +62,18 @@
6162
6263
object: [ 1, 2, abc ]
6364
65+
#. With ``brackets: {forbid: non-empty}``
66+
67+
the following code snippet would **PASS**:
68+
::
69+
70+
object: []
71+
72+
the following code snippet would **FAIL**:
73+
::
74+
75+
object: [ 1, 2, abc ]
76+
6477
#. With ``brackets: {min-spaces-inside: 0, max-spaces-inside: 0}``
6578
6679
the following code snippet would **PASS**:
@@ -129,7 +142,7 @@
129142

130143
ID = 'brackets'
131144
TYPE = 'token'
132-
CONF = {'forbid': bool,
145+
CONF = {'forbid': (bool, 'non-empty'),
133146
'min-spaces-inside': int,
134147
'max-spaces-inside': int,
135148
'min-spaces-inside-empty': int,
@@ -142,7 +155,15 @@
142155

143156

144157
def check(conf, token, prev, next, nextnext, context):
145-
if conf['forbid'] and isinstance(token, yaml.FlowSequenceStartToken):
158+
if (conf['forbid'] is True and
159+
isinstance(token, yaml.FlowSequenceStartToken)):
160+
yield LintProblem(token.start_mark.line + 1,
161+
token.end_mark.column + 1,
162+
'forbidden flow sequence')
163+
164+
elif (conf['forbid'] == 'non-empty' and
165+
isinstance(token, yaml.FlowSequenceStartToken) and
166+
not isinstance(next, yaml.FlowSequenceEndToken)):
146167
yield LintProblem(token.start_mark.line + 1,
147168
token.end_mark.column + 1,
148169
'forbidden flow sequence')

0 commit comments

Comments
 (0)