promtext-cli 0.1.2.dev84__tar.gz → 0.1.2.dev93__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.
@@ -1,13 +1,14 @@
1
1
  # Changes here will be overwritten by Copier.
2
- _commit: 0.5.11
2
+ _commit: 0.7.7
3
3
  _src_path: https://codeberg.org/margau/copier-python-uv.git
4
- code_dir: src
4
+ code_dir: promtext_cli
5
5
  container: false
6
6
  forgejo_publish: true
7
7
  forgejo_url: https://codeberg.org/margau/promtext-cli
8
- ignore_pylint: true
9
- ignore_ruff: true
10
- ignore_ruff_format: true
8
+ ignore_pylint: false
9
+ ignore_pytest: false
10
+ ignore_ruff: false
11
+ ignore_ruff_format: false
11
12
  project_description: Prometheus Textfile Tooling
12
13
  project_name: promtext-cli
13
14
  pypi_publish: true
@@ -11,7 +11,7 @@ jobs:
11
11
  commitlint-check:
12
12
  runs-on: docker
13
13
  container:
14
- image: codeberg.org/margau/buildenv-commitlint:latest@sha256:243d5a0bed5be48a06167e2f4eaa132b7548f3e93605601575fb8e2612e5da82
14
+ image: codeberg.org/margau/buildenv-commitlint:latest@sha256:8253a5665a32be5a1ec56589e85e9c40634ca43a3d3ec261b08759e8e87efc60
15
15
 
16
16
  steps:
17
17
  - uses: https://code.forgejo.org/actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -20,8 +20,8 @@ jobs:
20
20
  - name: Install the project
21
21
  run: uv sync --locked --all-extras --dev
22
22
  - name: check with ruff
23
- run: uv run ruff check src || exit 0
23
+ run: uv run ruff check promtext_cli tests
24
24
  - name: format with ruff
25
- run: uv run ruff format --check src || exit 0
25
+ run: uv run ruff format --check promtext_cli tests
26
26
  - name: check with pylint
27
- run: uv run pylint src || exit 0
27
+ run: uv run pylint promtext_cli tests # TODO: Check if there is a need for special pytest-related pylint rules
@@ -0,0 +1,25 @@
1
+ name: pytest
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ # non-main branches are handled by pull_request
8
+ pull_request:
9
+
10
+ jobs:
11
+ pytest:
12
+ runs-on: docker
13
+ container:
14
+ image: codeberg.org/margau/buildenv-uv:latest@sha256:aaaf8bd9bfbe276136de485eb397aad9dc569b0ae76473b12f16b0205fcf4be0
15
+
16
+ steps:
17
+ - uses: https://code.forgejo.org/actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
18
+ with:
19
+ fetch-depth: 0
20
+ - name: Install the project
21
+ run: uv sync --locked --all-extras --dev
22
+ - name: run pytest
23
+ run: uv run coverage run -m pytest -v
24
+ - name: show coverage
25
+ run: uv run coverage report -m
@@ -10,7 +10,7 @@ repos:
10
10
  stages: [commit-msg]
11
11
  args: []
12
12
  - repo: https://github.com/astral-sh/ruff-pre-commit
13
- rev: v0.15.12
13
+ rev: v0.15.13
14
14
  hooks:
15
15
  # Run the linter.
16
16
  - id: ruff-check
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: promtext-cli
3
- Version: 0.1.2.dev84
3
+ Version: 0.1.2.dev93
4
4
  Summary: Prometheus Textfile Tooling
5
5
  Project-URL: Documentation, https://codeberg.org/margau/promtext-cli/src/branch/main#readme
6
6
  Project-URL: Issues, https://codeberg.org/margau/promtext-cli/issues
@@ -1,5 +1,8 @@
1
1
  """promtext_cli is providing a CLI to cleanly update prometheus textfiles from scripts"""
2
2
 
3
+ # pylint: disable=C0116,R0914,R0912,R0915
4
+ # this rules will be fixed by a object-oriented refactoring
5
+
3
6
  import argparse
4
7
  from pathlib import Path
5
8
  import logging
@@ -8,37 +11,43 @@ import sys
8
11
  from prometheus_client.parser import text_string_to_metric_families
9
12
  from prometheus_client import CollectorRegistry, Gauge, write_to_textfile
10
13
 
14
+
11
15
  def promtext():
12
16
  # setup argpars
13
17
  # required file first
14
- parser = argparse.ArgumentParser(description='Prometheus textfile helper')
18
+ parser = argparse.ArgumentParser(description="Prometheus textfile helper")
15
19
  parser.add_argument(
16
- 'filename',
20
+ "filename",
17
21
  type=str,
18
- help='Path to existing or new prometheus textfile, will be updated'
19
- )
22
+ help="Path to existing or new prometheus textfile, will be updated",
23
+ )
20
24
 
21
25
  # metric name, required
22
- parser.add_argument(
23
- 'metric',
24
- type=str,
25
- help='metric name (new or updated)')
26
+ parser.add_argument("metric", type=str, help="metric name (new or updated)")
26
27
 
27
28
  # metric value as int/float, required
28
- parser.add_argument('value', type=float, help='metric value')
29
+ parser.add_argument("value", type=float, help="metric value")
29
30
 
30
31
  # metric documentation as optional argument
31
32
  parser.add_argument(
32
- '--docs', type=str,
33
- help='metric documentation', default="metric appended by promtext-cli")
33
+ "--docs",
34
+ type=str,
35
+ help="metric documentation",
36
+ default="metric appended by promtext-cli",
37
+ )
34
38
 
35
39
  # labels, key-value, minimum 0, repeatable
36
- parser.add_argument("--label", metavar="KEY=VALUE", help='label key=value pairs', action='append')
40
+ parser.add_argument(
41
+ "--label", metavar="KEY=VALUE", help="label key=value pairs", action="append"
42
+ )
37
43
 
38
44
  # log level from argparse
39
45
  parser.add_argument(
40
- '-v', '--verbose',
41
- action="store_const", dest="loglevel", const=logging.INFO,
46
+ "-v",
47
+ "--verbose",
48
+ action="store_const",
49
+ dest="loglevel",
50
+ const=logging.INFO,
42
51
  )
43
52
  args = parser.parse_args()
44
53
  logging.basicConfig(level=args.loglevel)
@@ -52,7 +61,7 @@ def promtext():
52
61
 
53
62
  # check if args.filename exists with pathlib
54
63
  if textfile.is_file():
55
- for f in text_string_to_metric_families(textfile.read_text()):
64
+ for f in text_string_to_metric_families(textfile.read_text(encoding="utf-8")):
56
65
  # per metric: iterate over samples, create metric in registry
57
66
  m = False
58
67
  samples = []
@@ -63,8 +72,13 @@ def promtext():
63
72
  labelnames = list(samples[0].labels.keys())
64
73
  # metric-type specific init
65
74
  if f.type == "gauge":
66
- m = Gauge(f.name, f.documentation,
67
- unit=f.unit, labelnames=labelnames, registry=registry)
75
+ m = Gauge(
76
+ f.name,
77
+ f.documentation,
78
+ unit=f.unit,
79
+ labelnames=labelnames,
80
+ registry=registry,
81
+ )
68
82
  else:
69
83
  # we don't support other types yet, continue in these cases
70
84
  logger.warning("unsupported metric type %s, dropping", f.type)
@@ -76,8 +90,11 @@ def promtext():
76
90
  else:
77
91
  m.set(s.value)
78
92
  metrics[f.name] = m
79
- logger.info("copy gauge metric %s with labels %s from old file",
80
- f.name, ', '.join(labelnames))
93
+ logger.info(
94
+ "copy gauge metric %s with labels %s from old file",
95
+ f.name,
96
+ ", ".join(labelnames),
97
+ )
81
98
  else:
82
99
  logger.warning("got empty metric %s from old file, dropping", f.name)
83
100
 
@@ -99,18 +116,24 @@ def promtext():
99
116
  labelvalues = labels.values()
100
117
  else:
101
118
  m = metrics[args.metric]
102
-
119
+
120
+ # There is no way to access existing labelnames directly
121
+ # pylint: disable=W0212
103
122
  old_labelnames = list(m._labelnames)
104
123
  for la in old_labelnames:
105
124
  logger.info("processing label %s", la)
106
- if la in labels: # labelvalues are needed in order!
125
+ if la in labels: # labelvalues are needed in order!
107
126
  labelvalues.append(labels[la])
108
127
  else:
109
128
  logger.error("previously known label '%s' missing, cannot update!", la)
110
129
  sys.exit(1)
111
130
  if len(old_labelnames) != len(labels.keys()):
112
- logger.error("labelnames for metric %s not the same, cannot update! Old: %s, New: %s",
113
- args.metric, old_labelnames, list(labels.keys()))
131
+ logger.error(
132
+ "labelnames for metric %s not the same, cannot update! Old: %s, New: %s",
133
+ args.metric,
134
+ old_labelnames,
135
+ list(labels.keys()),
136
+ )
114
137
  sys.exit(1)
115
138
  logger.info("updating metric %s", args.metric)
116
139
 
@@ -124,5 +147,6 @@ def promtext():
124
147
  write_to_textfile(args.filename, registry)
125
148
  logger.info("wrote to %s", args.filename)
126
149
 
127
- if __name__ == '__main__':
150
+
151
+ if __name__ == "__main__":
128
152
  promtext()
@@ -30,13 +30,19 @@ Source = "https://codeberg.org/margau/promtext-cli.git"
30
30
  [project.scripts]
31
31
  promtext = "promtext_cli.main:promtext"
32
32
 
33
+ [dependency-groups]
34
+ dev = [
35
+ "ruff>=0.15.13",
36
+ "pylint>=4.0.5",
37
+ "pytest>=9.0.3",
38
+ "coverage>=7.14.0",
39
+ "cli-test-helpers>=4.2.0",
40
+ ]
33
41
 
34
- # Dev Dependencies
35
42
  [tool.uv]
36
- dev-dependencies = [
37
- "ruff",
38
- "pylint",
39
- ]
40
43
  cache-keys = [{ file = "pyproject.toml" }, { git = { commit = true, tags = true } }]
41
44
 
45
+ [tool.coverage.run]
46
+ source = ["src", "tests"]
47
+
42
48
  # TODO: Dev/CI scripts for lint & co.
@@ -8,6 +8,7 @@
8
8
  "matchFileNames": [
9
9
  ".forgejo/workflows/commitlint.yaml",
10
10
  ".forgejo/workflows/lint.yaml",
11
+ ".forgejo/workflows/test.yaml",
11
12
  ".forgejo/workflows/publish.yaml",
12
13
  ".forgejo/workflows/container.yaml",
13
14
  "Containerfile"
@@ -18,6 +19,7 @@
18
19
  "matchFileNames": [
19
20
  ".forgejo/workflows/commitlint.yaml",
20
21
  ".forgejo/workflows/lint.yaml",
22
+ ".forgejo/workflows/test.yaml",
21
23
  ".forgejo/workflows/publish.yaml",
22
24
  ".forgejo/workflows/container.yaml",
23
25
  "Containerfile"
File without changes
@@ -0,0 +1,48 @@
1
+ # pylint: disable=R0801
2
+ """This script does blackbox-like testing of the promtext cli tool"""
3
+
4
+ import shutil
5
+ from cli_test_helpers import shell
6
+
7
+
8
+ def test_entrypoint():
9
+ """
10
+ Is entrypoint script installed? (pyproject.toml)
11
+ """
12
+ assert shutil.which("promtext")
13
+
14
+
15
+ def test_help():
16
+ """
17
+ Does the help command work?
18
+ """
19
+ result = shell("promtext --help")
20
+ assert result.exit_code == 0
21
+ assert "usage:" in result.stdout
22
+
23
+
24
+ def test_empty():
25
+ """
26
+ Does the command fails with no arguments?
27
+ """
28
+ result = shell("promtext")
29
+ assert result.exit_code == 2
30
+ assert "usage:" in result.stderr
31
+
32
+
33
+ def test_new_file(tmp_path):
34
+ """
35
+ Does the command create a new file with metrics content?
36
+ """
37
+ promfile = tmp_path / "new_file.prom"
38
+ result = shell(f"promtext {promfile} test_metric 0")
39
+ assert result.exit_code == 0
40
+ assert promfile.exists()
41
+ assert promfile.read_text() == (
42
+ "# HELP test_metric metric appended by promtext-cli"
43
+ "\n"
44
+ "# TYPE test_metric gauge"
45
+ "\n"
46
+ "test_metric 0.0"
47
+ "\n"
48
+ )
@@ -0,0 +1,342 @@
1
+ # pylint: disable=R0801,W0511
2
+ """This script does functional testing by calling the methods directly"""
3
+
4
+ from cli_test_helpers import ArgvContext
5
+ import pytest
6
+
7
+ import promtext_cli.main
8
+
9
+
10
+ def test_new_file(tmp_path):
11
+ """
12
+ Does the command create a new file with metrics content?
13
+ """
14
+ promfile = tmp_path / "new_file.prom"
15
+ with ArgvContext("promtext", str(promfile), "test_metric", "0"):
16
+ promtext_cli.main.promtext()
17
+ assert promfile.exists()
18
+ assert promfile.read_text() == (
19
+ "# HELP test_metric metric appended by promtext-cli"
20
+ "\n"
21
+ "# TYPE test_metric gauge"
22
+ "\n"
23
+ "test_metric 0.0"
24
+ "\n"
25
+ )
26
+
27
+
28
+ def test_labels(tmp_path):
29
+ """
30
+ Does the command create a new file with metrics content?
31
+ """
32
+ promfile = tmp_path / "label_file.prom"
33
+ with ArgvContext(
34
+ "promtext", "--label", "testlabel=testvalue", str(promfile), "test_metric", 0
35
+ ):
36
+ promtext_cli.main.promtext()
37
+ assert promfile.exists()
38
+ assert promfile.read_text() == (
39
+ "# HELP test_metric metric appended by promtext-cli"
40
+ "\n"
41
+ "# TYPE test_metric gauge"
42
+ "\n"
43
+ 'test_metric{testlabel="testvalue"} 0.0'
44
+ "\n"
45
+ )
46
+
47
+
48
+ def test_existing_metric_append_metric(tmp_path):
49
+ """
50
+ Does the command append a new metric to an existing file
51
+ with metrics content and preserve existing metrics?
52
+ """
53
+ promfile = tmp_path / "existing_file.prom"
54
+ promfile.write_text(
55
+ "# HELP existing_metric metric appended by promtext-cli"
56
+ "\n"
57
+ "# TYPE existing_metric gauge"
58
+ "\n"
59
+ 'existing_metric{testlabel="testvalue"} 0.0'
60
+ "\n"
61
+ )
62
+ with ArgvContext(
63
+ "promtext", "--label", "testlabel=testvalue", str(promfile), "new_metric", 0
64
+ ):
65
+ promtext_cli.main.promtext()
66
+ assert promfile.exists()
67
+ assert promfile.read_text() == (
68
+ "# HELP existing_metric metric appended by promtext-cli"
69
+ "\n"
70
+ "# TYPE existing_metric gauge"
71
+ "\n"
72
+ 'existing_metric{testlabel="testvalue"} 0.0'
73
+ "\n"
74
+ "# HELP new_metric metric appended by promtext-cli"
75
+ "\n"
76
+ "# TYPE new_metric gauge"
77
+ "\n"
78
+ 'new_metric{testlabel="testvalue"} 0.0'
79
+ "\n"
80
+ )
81
+
82
+
83
+ def test_existing_metric_append_labelvalue(tmp_path):
84
+ """
85
+ Does the command append a new metric to an existing file
86
+ with metrics content and preserve existing metrics?
87
+ """
88
+ promfile = tmp_path / "existing_file.prom"
89
+ promfile.write_text(
90
+ "# HELP existing_metric metric appended by promtext-cli"
91
+ "\n"
92
+ "# TYPE existing_metric gauge"
93
+ "\n"
94
+ 'existing_metric{testlabel="existing"} 0.0'
95
+ "\n"
96
+ )
97
+ with ArgvContext(
98
+ "promtext", "--label", "testlabel=new", str(promfile), "existing_metric", 0
99
+ ):
100
+ promtext_cli.main.promtext()
101
+ assert promfile.exists()
102
+ assert promfile.read_text() == (
103
+ "# HELP existing_metric metric appended by promtext-cli"
104
+ "\n"
105
+ "# TYPE existing_metric gauge"
106
+ "\n"
107
+ 'existing_metric{testlabel="existing"} 0.0'
108
+ "\n"
109
+ 'existing_metric{testlabel="new"} 0.0'
110
+ "\n"
111
+ )
112
+
113
+
114
+ def test_existing_metric_multilabel(tmp_path):
115
+ """
116
+ Does the command append a new metric to an existing file
117
+ with metrics content and preserve existing metrics?
118
+ """
119
+ promfile = tmp_path / "existing_file.prom"
120
+ promfile.write_text(
121
+ "# HELP existing_metric metric appended by promtext-cli"
122
+ "\n"
123
+ "# TYPE existing_metric gauge"
124
+ "\n"
125
+ 'existing_metric{first="existing", second="existing"} 0.0'
126
+ "\n"
127
+ )
128
+ with ArgvContext(
129
+ "promtext",
130
+ "--label",
131
+ "first=new",
132
+ "--label",
133
+ "second=new",
134
+ str(promfile),
135
+ "existing_metric",
136
+ "42",
137
+ ):
138
+ promtext_cli.main.promtext()
139
+ assert promfile.exists()
140
+ assert promfile.read_text() == (
141
+ "# HELP existing_metric metric appended by promtext-cli"
142
+ "\n"
143
+ "# TYPE existing_metric gauge"
144
+ "\n"
145
+ 'existing_metric{first="existing",second="existing"} 0.0'
146
+ "\n"
147
+ 'existing_metric{first="new",second="new"} 42.0'
148
+ "\n"
149
+ )
150
+
151
+
152
+ def test_existing_metric_overwrite(tmp_path):
153
+ """
154
+ Does the command overwrite a metric/labelset
155
+ """
156
+ promfile = tmp_path / "existing_file.prom"
157
+ promfile.write_text(
158
+ "# HELP existing_metric metric appended by promtext-cli"
159
+ "\n"
160
+ "# TYPE existing_metric gauge"
161
+ "\n"
162
+ 'existing_metric{testlabel="existing"} 0.0'
163
+ "\n"
164
+ )
165
+ with ArgvContext(
166
+ "promtext",
167
+ "--label",
168
+ "testlabel=existing",
169
+ str(promfile),
170
+ "existing_metric",
171
+ "42",
172
+ ):
173
+ promtext_cli.main.promtext()
174
+ assert promfile.exists()
175
+ assert promfile.read_text() == (
176
+ "# HELP existing_metric metric appended by promtext-cli"
177
+ "\n"
178
+ "# TYPE existing_metric gauge"
179
+ "\n"
180
+ 'existing_metric{testlabel="existing"} 42.0'
181
+ "\n"
182
+ )
183
+
184
+
185
+ def test_existing_metric_plain(tmp_path):
186
+ """
187
+ Does the command overwrite a metric without a label?
188
+ """
189
+ promfile = tmp_path / "existing_file.prom"
190
+ promfile.write_text(
191
+ "# HELP existing_metric metric appended by promtext-cli"
192
+ "\n"
193
+ "# TYPE existing_metric gauge"
194
+ "\n"
195
+ "existing_metric 0.0"
196
+ "\n"
197
+ )
198
+ with ArgvContext("promtext", str(promfile), "existing_metric", "42"):
199
+ promtext_cli.main.promtext()
200
+ assert promfile.exists()
201
+ assert promfile.read_text() == (
202
+ "# HELP existing_metric metric appended by promtext-cli"
203
+ "\n"
204
+ "# TYPE existing_metric gauge"
205
+ "\n"
206
+ "existing_metric 42.0"
207
+ "\n"
208
+ )
209
+
210
+
211
+ def test_existing_metric_labeldrop(tmp_path, capsys):
212
+ """
213
+ missing labels are not possible, promtext should fail
214
+ """
215
+ promfile = tmp_path / "existing_file.prom"
216
+ promfile.write_text(
217
+ "# HELP existing_metric metric appended by promtext-cli"
218
+ "\n"
219
+ "# TYPE existing_metric gauge"
220
+ "\n"
221
+ 'existing_metric{testlabel="existing"} 0.0'
222
+ "\n"
223
+ )
224
+
225
+ with (
226
+ ArgvContext("promtext", str(promfile), "existing_metric", "42"),
227
+ pytest.raises(SystemExit) as pytest_wrapped_e,
228
+ ):
229
+ promtext_cli.main.promtext()
230
+ assert promfile.exists()
231
+ assert promfile.read_text() == (
232
+ "# HELP existing_metric metric appended by promtext-cli"
233
+ "\n"
234
+ "# TYPE existing_metric gauge"
235
+ "\n"
236
+ 'existing_metric{testlabel="existing"} 0.0'
237
+ "\n"
238
+ ) # the content is not changed
239
+ # check that promtext exits correctly
240
+ assert pytest_wrapped_e.type is SystemExit
241
+ assert pytest_wrapped_e.value.code == 1
242
+ captured = capsys.readouterr()
243
+ assert (
244
+ "ERROR:promtext_cli.main:previously known label 'testlabel' missing, cannot update!"
245
+ in captured.err
246
+ )
247
+
248
+
249
+ def test_existing_metric_labelchange(tmp_path, capsys):
250
+ """
251
+ changing labels are not possible, promtext should fail
252
+ """
253
+ promfile = tmp_path / "existing_file.prom"
254
+ promfile.write_text(
255
+ "# HELP existing_metric metric appended by promtext-cli"
256
+ "\n"
257
+ "# TYPE existing_metric gauge"
258
+ "\n"
259
+ 'existing_metric{existinglabel="existing"} 0.0'
260
+ "\n"
261
+ )
262
+
263
+ with (
264
+ ArgvContext(
265
+ "promtext",
266
+ "--label",
267
+ "newlabel=new",
268
+ str(promfile),
269
+ "existing_metric",
270
+ "42",
271
+ ),
272
+ pytest.raises(SystemExit) as pytest_wrapped_e,
273
+ ):
274
+ promtext_cli.main.promtext()
275
+ assert promfile.exists()
276
+ assert promfile.read_text() == (
277
+ "# HELP existing_metric metric appended by promtext-cli"
278
+ "\n"
279
+ "# TYPE existing_metric gauge"
280
+ "\n"
281
+ 'existing_metric{existinglabel="existing"} 0.0'
282
+ "\n"
283
+ ) # the content is not changed
284
+ # check that promtext exits correctly
285
+ assert pytest_wrapped_e.type is SystemExit
286
+ assert pytest_wrapped_e.value.code == 1
287
+ captured = capsys.readouterr()
288
+ assert (
289
+ "ERROR:promtext_cli.main:previously known label 'existinglabel' missing, cannot update!"
290
+ in captured.err
291
+ )
292
+
293
+
294
+ def test_existing_metric_labeladd(tmp_path, capsys):
295
+ """
296
+ adding new labels are not possible, promtext should fail
297
+ """
298
+ promfile = tmp_path / "existing_file.prom"
299
+ promfile.write_text(
300
+ "# HELP existing_metric metric appended by promtext-cli"
301
+ "\n"
302
+ "# TYPE existing_metric gauge"
303
+ "\n"
304
+ 'existing_metric{existinglabel="existing"} 0.0'
305
+ "\n"
306
+ )
307
+
308
+ with (
309
+ ArgvContext(
310
+ "promtext",
311
+ "--label",
312
+ "existinglabel=existing",
313
+ "--label",
314
+ "newlabel=new",
315
+ str(promfile),
316
+ "existing_metric",
317
+ "42",
318
+ ),
319
+ pytest.raises(SystemExit) as pytest_wrapped_e,
320
+ ):
321
+ promtext_cli.main.promtext()
322
+ assert promfile.exists()
323
+ assert promfile.read_text() == (
324
+ "# HELP existing_metric metric appended by promtext-cli"
325
+ "\n"
326
+ "# TYPE existing_metric gauge"
327
+ "\n"
328
+ 'existing_metric{existinglabel="existing"} 0.0'
329
+ "\n"
330
+ ) # the content is not changed
331
+ # check that promtext exits correctly
332
+ assert pytest_wrapped_e.type is SystemExit
333
+ assert pytest_wrapped_e.value.code == 1
334
+ captured = capsys.readouterr()
335
+ assert (
336
+ "ERROR:promtext_cli.main:labelnames for metric existing_metric not the same, cannot update"
337
+ in captured.err
338
+ )
339
+
340
+
341
+ # TODO: Test docs in promtext
342
+ # TODO: Test non-gauge-values