toml_empty 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 18f7758393bd1544a64b10d28ab7a83340f07c14d90a2e6177b362abd43debea
4
+ data.tar.gz: 89879113263d7ecd003a6f0b950dcfe1657d45a5296532a711ff82285c249e37
5
+ SHA512:
6
+ metadata.gz: 45613e3e99d0123782583bdcf4fe98e010353e52b33519da766a9bb5e9ee9e41ccb9dac5ff492467fb4c28f5a22b71e37c6180c3bcf905e2e6d554f9c39a3a9a
7
+ data.tar.gz: fbbb621d8725790a55aad4da7b355c301fd0f0869ffa77b20d05dd6b56dbe48eeb7c527117933347f23d11c314098f2b609d483e8e2dcaefc31ce179ae221740
data/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ ## 0.3.0 / 2020-06-09
2
+
3
+ - Fixes TOML to work with version 2.0 of Parslet
4
+
5
+ ## 0.2.0 / 2017-11-11
6
+
7
+ - Add support for underscored Integers and Floats
8
+ - Fixes TOML to work with version 1.8.0 of Parslet
9
+
10
+ ## 0.1.2 / 2014-10-16
11
+
12
+ - Add support for `CR` and `CRLF` newlines (#13)
13
+ - Add support for generating TOML from Ruby `Hash`es (#36)
14
+ - Add a script interface for @BurntSushi's `toml-test` utility (#38)
15
+
16
+ ## 0.1.1 / 2014-02-17
17
+
18
+ - Add license to gemspec (#26)
19
+ - Loosen `multi_json` dependency version specified (#27)
20
+ - `Generator` should print empty hash tables but not keys without values (#28)
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) Tom Preston-Werner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # TOML
2
+
3
+ A sane configuration format from @mojombo. More information here: https://github.com/mojombo/toml
4
+
5
+ This is far superior to YAML and JSON because it doesn't suck. Really it doesn't.
6
+
7
+ ## Usage
8
+
9
+ Add to your Gemfile:
10
+
11
+ ```ruby
12
+ gem "toml", "~> 0.3.0"
13
+ ```
14
+
15
+ It's simple, really.
16
+
17
+ ```ruby
18
+ content = <<-TOML
19
+
20
+ # Hello, this is an example.
21
+ [things]
22
+ other = "things"
23
+ what = 900000
24
+
25
+ TOML
26
+
27
+ parser = TOML::Parser.new(content).parsed
28
+ # => { "things" => { "other" => "things", "what" => 900000 } }
29
+ ```
30
+
31
+ You can also use the same API as `YAML` if you'd like:
32
+
33
+ ```ruby
34
+ TOML.load("thing = 9")
35
+ # => {"thing" => 9}
36
+
37
+ TOML.load_file("my_file.toml")
38
+ # => {"whatever" => "keys"}
39
+ ```
40
+
41
+ There's also a beta feature for generating a TOML file from a Ruby hash. Please note this will likely not give beautiful output right now.
42
+
43
+ ```ruby
44
+ hash = {
45
+ "integer" => 1,
46
+ "float" => 3.14159,
47
+ "true" => true,
48
+ "false" => false,
49
+ "string" => "hi",
50
+ "array" => [[1], [2], [3]],
51
+ "key" => {
52
+ "group" => {
53
+ "value" => "lol"
54
+ }
55
+ }
56
+ }
57
+ doc = TOML::Generator.new(hash).body
58
+ # doc will be a string containing a proper TOML document.
59
+ ```
60
+
61
+ ## Contributors
62
+
63
+ Written by Jeremy McAnally (@jm) and Dirk Gadsden (@dirk) based on TOML from Tom Preston-Werner (@mojombo).
data/lib/toml.rb ADDED
@@ -0,0 +1,25 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'time'
4
+ require 'parslet'
5
+
6
+ require 'toml/version'
7
+ require 'toml/key'
8
+ require 'toml/table'
9
+ require 'toml/parslet'
10
+ require 'toml/transformer'
11
+ require 'toml/parser'
12
+ require 'toml/generator'
13
+ # Don't do monkey-patching by default. Only pulled in by TOML::Generator
14
+ # if needed (see generator.rb line 27).
15
+ # require 'toml/monkey_patch
16
+
17
+ module TOML
18
+ def self.load(content)
19
+ Parser.new(content).parsed
20
+ end
21
+
22
+ def self.load_file(path)
23
+ Parser.new(File.read(path)).parsed
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+
2
+ module TOML
3
+ class Generator
4
+ attr_reader :body, :doc
5
+
6
+ def initialize(doc)
7
+ # Ensure all the to_toml methods are injected into the base Ruby classes
8
+ # used by TOML.
9
+ self.class.inject!
10
+
11
+ @doc = doc
12
+ @body = doc.to_toml
13
+
14
+ return @body
15
+ end
16
+
17
+ # Whether or not the injections have already been done.
18
+ @@injected = false
19
+ # Inject to_toml methods into the Ruby classes used by TOML (booleans,
20
+ # String, Numeric, Array). You can add to_toml methods to your own classes
21
+ # to allow them to be easily serialized by the generator (and it will shout
22
+ # if something doesn't have a to_toml method).
23
+ def self.inject!
24
+ return if @@injected
25
+ require 'toml/monkey_patch'
26
+ @@injected = true
27
+ end
28
+ end#Generator
29
+ end#TOML
data/lib/toml/key.rb ADDED
@@ -0,0 +1,10 @@
1
+ module TOML
2
+ class Key
3
+ attr_reader :key, :value
4
+
5
+ def initialize(key, value)
6
+ @key = key
7
+ @value = value
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,89 @@
1
+ # Adds to_toml methods to base Ruby classes used by the generator.
2
+ class Object
3
+ def toml_table?
4
+ self.kind_of?(Hash)
5
+ end
6
+ def toml_table_array?
7
+ self.kind_of?(Array) && self.first.toml_table?
8
+ end
9
+ end
10
+ class Hash
11
+ def to_toml(path = "")
12
+ return "" if self.empty?
13
+
14
+ tables = {}
15
+ values = {}
16
+ self.keys.sort.each do |key|
17
+ val = self[key]
18
+ if val.kind_of?(NilClass)
19
+ next
20
+ elsif val.toml_table? || val.toml_table_array?
21
+ tables[key] = val
22
+ else
23
+ values[key] = val
24
+ end
25
+ end
26
+
27
+ toml = ""
28
+ values.each do |key, val|
29
+ toml << "#{key} = #{val.to_toml(key)}\n"
30
+ end
31
+
32
+ tables.each do |key, val|
33
+ key = "#{path}.#{key}" unless path.empty?
34
+ toml_val = val.to_toml(key)
35
+ if toml_val.empty?
36
+ toml << "\n[#{key}]\n"
37
+ else
38
+ if val.toml_table?
39
+ non_table_vals = val.values.reject do |v|
40
+ v.toml_table? || v.toml_table_array?
41
+ end
42
+
43
+ # Only add the table key if there are non table values.
44
+ if non_table_vals.length > 0
45
+ toml << "\n[#{key}]\n"
46
+ end
47
+ end
48
+ toml << toml_val
49
+ end
50
+ end
51
+
52
+ toml
53
+ end
54
+ end
55
+ class Array
56
+ def to_toml(path = "")
57
+ unless self.map(&:class).uniq.length == 1
58
+ raise "All array values must be the same type"
59
+ end
60
+
61
+ if self.first.toml_table?
62
+ toml = ""
63
+ self.each do |val|
64
+ toml << "\n[[#{path}]]\n"
65
+ toml << val.to_toml(path)
66
+ end
67
+ return toml
68
+ else
69
+ "[" + self.map {|v| v.to_toml(path) }.join(",") + "]"
70
+ end
71
+ end
72
+ end
73
+ class TrueClass
74
+ def to_toml(path = ""); "true"; end
75
+ end
76
+ class FalseClass
77
+ def to_toml(path = ""); "false"; end
78
+ end
79
+ class String
80
+ def to_toml(path = ""); self.inspect; end
81
+ end
82
+ class Numeric
83
+ def to_toml(path = ""); self.to_s; end
84
+ end
85
+ class DateTime
86
+ def to_toml(path = "")
87
+ self.to_time.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
88
+ end
89
+ end
@@ -0,0 +1,99 @@
1
+ module TOML
2
+ class Parser
3
+ attr_reader :parsed
4
+
5
+ def initialize(markup)
6
+ # Make sure we have a newline on the end
7
+
8
+ markup += "\n" unless markup.end_with?("\n") || markup.length == 0
9
+ begin
10
+ tree = Parslet.new.parse(markup)
11
+ rescue Parslet::ParseFailed => failure
12
+ puts failure.cause.ascii_tree
13
+ end
14
+
15
+
16
+ parts = Transformer.new.apply(tree) || []
17
+ @parsed = {}
18
+ @current = @parsed
19
+ @current_path = ''
20
+
21
+ parts.each do |part|
22
+ if part.is_a? Key
23
+ # If @current is an array then we're in a key-group
24
+ if @current.is_a? Array
25
+ # Make sure there's a table to work with.
26
+ @current << {} if @current.last.nil?
27
+ # Set the key on the table.
28
+ @current.last[part.key] = part.value
29
+ next
30
+ end
31
+ # Make sure the key isn't already set
32
+ if !@current.is_a?(Hash) || @current.has_key?(part.key)
33
+ err = "Cannot override key '#{part.key}'"
34
+ unless @current_path.empty?
35
+ err += " at path '#{@current_path}'"
36
+ end
37
+ raise err
38
+ end
39
+ # Set the key-value into the current hash
40
+ @current[part.key] = part.value
41
+ elsif part.is_a?(TableArray)
42
+ resolve_table_array(part)
43
+ elsif part.is_a?(Table)
44
+ resolve_table(part)
45
+ else
46
+ raise "Unrecognized part: #{part.inspect}"
47
+ end
48
+ end
49
+ end
50
+
51
+ def resolve_table_array(t)
52
+ @current = @parsed
53
+ path = t.name.dup
54
+ @current_path = path.join('.')
55
+ while n = path.shift
56
+ # If it's a table-array then get the last item.
57
+ @current = @current.last if @current.is_a? Array
58
+
59
+ # If it's the last item:
60
+ if path.length == 0
61
+ # If the current table has an item:
62
+ if @current.has_key?(n)
63
+ # And that item is already a table-array:
64
+ if @current[n].is_a? Array
65
+ # Then add an item to that table-array.
66
+ @current[n] << {}
67
+ else
68
+ raise "Cannot override table array '#{t.name.join '.'}'"
69
+ end
70
+ else
71
+ # Create a new table array if nothing exists here.
72
+ @current[n] = []
73
+ end
74
+ elsif @current.has_key? n
75
+ # Don't do anything if we're just moving into tables.
76
+ else
77
+ @current[n] = {}
78
+ end
79
+ @current = @current[n]
80
+ end
81
+ end
82
+
83
+ def resolve_table(t)
84
+ @current = @parsed
85
+
86
+ path = t.name.dup
87
+ @current_path = path.join('.')
88
+ while k = path.shift
89
+ # If it's a table-array then get the last item.
90
+ @current = @current.last if @current.is_a? Array
91
+ # Create a new table if one doesn't exist.
92
+ @current[k] = {} if !@current.has_key? k
93
+ # Move into the table.
94
+ @current = @current[k]
95
+ end
96
+ end#/resolve_key_group
97
+
98
+ end
99
+ end
@@ -0,0 +1,103 @@
1
+ module TOML
2
+ class Parslet < ::Parslet::Parser
3
+ rule(:document) {
4
+ all_space >>
5
+ (table | table_array | key_value | comment_line).repeat >>
6
+ all_space
7
+ }
8
+ root :document
9
+
10
+ rule(:value) {
11
+ array |
12
+ string |
13
+ datetime.as(:datetime) |
14
+ float.as(:float) |
15
+ integer.as(:integer) |
16
+ boolean
17
+ }
18
+
19
+ # Finding comments in multiline arrays requires accepting a bunch of
20
+ # possible newlines and stuff before the comment
21
+ rule(:array_comments) { (all_space >> comment_line).repeat }
22
+
23
+ rule(:array) {
24
+ str("[") >> all_space >> array_comments >>
25
+ ( array_comments >> # Match any comments on first line
26
+ all_space >> value >> array_comments >>
27
+ (
28
+ # Separator followed by any comments
29
+ all_space >> str(",") >> array_comments >>
30
+ # Value followed by any comments
31
+ all_space >> value >> array_comments
32
+ ).repeat >>
33
+ (all_space >> str(",")).maybe >> # possible trailing comma
34
+ all_space >> array_comments # Grab any remaining comments just in case
35
+ ).maybe.as(:array) >> str("]")
36
+ }
37
+
38
+ rule(:key_value) {
39
+ space >> key.as(:key) >>
40
+ space >> str("=") >>
41
+ space >> value.as(:value) >>
42
+ space >> comment.maybe >> newline >> all_space
43
+ }
44
+ rule(:table) {
45
+ space >> str("[") >>
46
+ table_name.as(:table) >>
47
+ str("]") >>
48
+ space >> comment.maybe >> newline >> all_space
49
+ }
50
+ rule(:table_array) {
51
+ space >> str("[[") >>
52
+ table_name.as(:table_array) >>
53
+ str("]]") >>
54
+ space >> comment.maybe >> str("\n") >> all_space
55
+ }
56
+
57
+ rule(:key) { match["^. \t\\]"].repeat(1) }
58
+ rule(:table_name) { key.as(:key) >> (str(".") >> key.as(:key)).repeat }
59
+
60
+ rule(:comment_line) { comment >> newline >> all_space }
61
+ rule(:comment) { str("#") >> match["^\n"].repeat }
62
+
63
+ rule(:space) { match[" \t"].repeat }
64
+ rule(:all_space) { match[" \t\r\n"].repeat }
65
+ rule(:newline) { str("\r").maybe >> str("\n") | str("\r") >> str("\n").maybe }
66
+
67
+ rule(:string) {
68
+ str('"') >> (
69
+ match["^\"\\\\"] |
70
+ (str("\\") >> match["0tnr\"\\\\"])
71
+ ).repeat.as(:string) >> str('"')
72
+ }
73
+
74
+ rule(:sign) { str("-") }
75
+ rule(:sign?) { sign.maybe }
76
+
77
+ rule(:integer) {
78
+ str("0") | sign? >>
79
+ (match["1-9"] >> (match["_"].maybe >> match["0-9"]).repeat)
80
+ }
81
+ rule(:float) {
82
+ sign? >>
83
+ (match["0-9"] >> (match["_"].maybe >> match["0-9"]).repeat) >> str(".") >>
84
+ (match["0-9"] >> (match["_"].maybe >> match["0-9"]).repeat)
85
+ }
86
+
87
+ rule(:boolean) { str("true").as(:true) | str("false").as(:false) }
88
+
89
+ rule(:date) {
90
+ match["0-9"].repeat(4,4) >> str("-") >>
91
+ match["0-9"].repeat(2,2) >> str("-") >>
92
+ match["0-9"].repeat(2,2)
93
+ }
94
+
95
+ rule(:time) {
96
+ match["0-9"].repeat(2,2) >> str(":") >>
97
+ match["0-9"].repeat(2,2) >> str(":") >>
98
+ match["0-9"].repeat(2,2)
99
+ }
100
+
101
+ rule(:datetime) { date >> str("T") >> time >> str("Z") }
102
+ end
103
+ end
data/lib/toml/table.rb ADDED
@@ -0,0 +1,10 @@
1
+ module TOML
2
+ class Table
3
+ # :name is array of strings
4
+ attr_reader :name
5
+ def initialize(name)
6
+ @name = name
7
+ end
8
+ end
9
+ class TableArray < Table; end
10
+ end
@@ -0,0 +1,115 @@
1
+ module TOML
2
+
3
+ class Transformer < ::Parslet::Transform
4
+ # Utility to properly handle escape sequences in parsed string.
5
+ def self.parse_string(val)
6
+ e = val.length
7
+ s = 0
8
+ o = []
9
+ while s < e
10
+ if val[s].chr == "\\"
11
+ s += 1
12
+ case val[s].chr
13
+ when "t"
14
+ o << "\t"
15
+ when "n"
16
+ o << "\n"
17
+ when "\\"
18
+ o << "\\"
19
+ when '"'
20
+ o << '"'
21
+ when "r"
22
+ o << "\r"
23
+ when "0"
24
+ o << "\0"
25
+ else
26
+ raise "Unexpected escape character: '\\#{val[s]}'"
27
+ end
28
+ else
29
+ o << val[s].chr
30
+ end
31
+ s += 1
32
+ end
33
+ o.join
34
+ end
35
+
36
+ # Clean up arrays
37
+ # rule(:array => subtree(:ar)) { ar.is_a?(Array) ? ar : [ar] }
38
+
39
+ # Empty file
40
+ rule('') {
41
+ nil
42
+ }
43
+
44
+ # Clean up simple value hashes
45
+ rule(:integer => simple(:i)) { i.to_i }
46
+ rule(:float => simple(:f)) { f.to_f }
47
+ rule(:string => simple(:s)) {
48
+ Transformer.parse_string(s.to_s)
49
+ }
50
+ rule(:string => sequence(:s)) {
51
+ raise "Unexpected string-sequence: #{s.inspect}" unless s.empty?
52
+ ""
53
+ }
54
+ rule(:datetime => simple(:d)) { DateTime.iso8601(d) }
55
+ rule(:true => simple(:b)) { true }
56
+ rule(:false => simple(:b)) { false }
57
+
58
+ rule(:key => simple(:k), :value => simple(:v)) { Key.new(k.to_s, v) }
59
+
60
+ # New array cleanup
61
+ # TODO: Make this more readable/understandable.
62
+ def self.visit_array(h)
63
+ if h.is_a? Hash
64
+ # If it's an {:array => ...} hash
65
+ a = h[:array]
66
+ if a.is_a? Array
67
+ # If the value is already an array
68
+ a = a.map {|v| visit_array(v) }
69
+ classes = a.map {|v|
70
+ # Grab the class, with a little exception for true and false since
71
+ # they're different classes (TrueClass and FalseClass).
72
+ (v == true || v == false) ? true : v.class
73
+ }
74
+ if classes.uniq.length != 1
75
+ raise "Conflicting types in array: " + \
76
+ classes.map(&:to_s).join(", ")
77
+ end
78
+ return a
79
+ else
80
+ # Turn the value into an array
81
+ return [visit_array(a)].compact
82
+ end
83
+ else
84
+ # Plain old non-hash value
85
+ return h
86
+ end
87
+ end
88
+ rule(:key => simple(:k), :value => subtree(:v)) {
89
+ Key.new(k.to_s, Transformer.visit_array(v))
90
+ }
91
+
92
+ # Make key hashes (inside key_groups) just be strings
93
+ rule(:key => simple(:k)) { k }
94
+
95
+ # Captures array-like key-groups
96
+ rule(:table => subtree(:kg)) {
97
+ Table.new(kg.map &:to_s)
98
+ }
99
+
100
+ # Then objectify the key_groups
101
+ rule(:table => simple(:kg)) {
102
+ Table.new([kg.to_s])
103
+ }
104
+
105
+ # Multi-part (a.b.c) table-arrays
106
+ rule(:table_array => subtree(:names)) {
107
+ TableArray.new(names.map &:to_s)
108
+ }
109
+
110
+ # Single name table-arrays
111
+ rule(:table_array => simple(:name)) {
112
+ TableArray.new([name.to_s])
113
+ }
114
+ end
115
+ end
@@ -0,0 +1,3 @@
1
+ module TOML
2
+ VERSION = '0.1.0'
3
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: toml_empty
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy McAnally
8
+ - Dirk Gadsden
9
+ - Guillaume Virlet
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2021-05-13 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: parslet
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: 1.8.0
22
+ - - "<"
23
+ - !ruby/object:Gem::Version
24
+ version: 3.0.0
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 1.8.0
32
+ - - "<"
33
+ - !ruby/object:Gem::Version
34
+ version: 3.0.0
35
+ - !ruby/object:Gem::Dependency
36
+ name: rake
37
+ requirement: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ type: :development
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ description: Parse your TOML (allow empty group), seriously.
50
+ email: github@virlet.org
51
+ executables: []
52
+ extensions: []
53
+ extra_rdoc_files:
54
+ - README.md
55
+ - LICENSE
56
+ - CHANGELOG.md
57
+ files:
58
+ - CHANGELOG.md
59
+ - LICENSE
60
+ - README.md
61
+ - lib/toml.rb
62
+ - lib/toml/generator.rb
63
+ - lib/toml/key.rb
64
+ - lib/toml/monkey_patch.rb
65
+ - lib/toml/parser.rb
66
+ - lib/toml/parslet.rb
67
+ - lib/toml/table.rb
68
+ - lib/toml/transformer.rb
69
+ - lib/toml/version.rb
70
+ homepage: http://github.com/doc75/toml
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options:
76
+ - "--charset=UTF-8"
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubygems_version: 3.1.6
91
+ signing_key:
92
+ specification_version: 2
93
+ summary: Parse your TOML (allow empty group).
94
+ test_files: []