agent-first-data 0.13.1__tar.gz → 0.13.2__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.
Files changed (18) hide show
  1. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/PKG-INFO +2 -2
  2. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/README.md +1 -1
  3. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/agent_first_data/__init__.py +4 -0
  4. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/agent_first_data/format.py +55 -3
  5. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/agent_first_data.egg-info/PKG-INFO +2 -2
  6. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/pyproject.toml +1 -1
  7. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/tests/test_format.py +8 -0
  8. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/agent_first_data/afdata_logging.py +0 -0
  9. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/agent_first_data/cli.py +0 -0
  10. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/agent_first_data/skill.py +0 -0
  11. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/agent_first_data.egg-info/SOURCES.txt +0 -0
  12. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/agent_first_data.egg-info/dependency_links.txt +0 -0
  13. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/agent_first_data.egg-info/top_level.txt +0 -0
  14. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/setup.cfg +0 -0
  15. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/tests/test_afdata_logging.py +0 -0
  16. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/tests/test_cli.py +0 -0
  17. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/tests/test_no_stderr_policy.py +0 -0
  18. {agent_first_data-0.13.1 → agent_first_data-0.13.2}/tests/test_skill.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-first-data
3
- Version: 0.13.1
3
+ Version: 0.13.2
4
4
  Summary: A naming convention that lets AI agents understand your data without being told what it means.
5
5
  License-Expression: MIT
6
6
  Project-URL: Repository, https://github.com/agentfirstkit/agent-first-data
@@ -29,7 +29,7 @@ print(output_json(value))
29
29
  print(output_plain(value))
30
30
  ```
31
31
 
32
- Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, and `cli_handle_version_or_continue`.
32
+ Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, and `cli_handle_version_or_continue`.
33
33
 
34
34
  Logging is available through `init_logging_json`, `init_logging_plain`, `init_logging_yaml`, `span`, and `get_logger`.
35
35
 
@@ -20,7 +20,7 @@ print(output_json(value))
20
20
  print(output_plain(value))
21
21
  ```
22
22
 
23
- Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, and `cli_handle_version_or_continue`.
23
+ Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, and `cli_handle_version_or_continue`.
24
24
 
25
25
  Logging is available through `init_logging_json`, `init_logging_plain`, `init_logging_yaml`, `span`, and `get_logger`.
26
26
 
@@ -24,6 +24,8 @@ from agent_first_data.format import (
24
24
  redact_url_secrets_with_options,
25
25
  parse_size,
26
26
  normalize_utc_offset,
27
+ is_valid_rfc3339_date,
28
+ is_valid_rfc3339_time,
27
29
  )
28
30
 
29
31
  from agent_first_data.afdata_logging import (
@@ -87,6 +89,8 @@ __all__ = [
87
89
  "redact_url_secrets_with_options",
88
90
  "parse_size",
89
91
  "normalize_utc_offset",
92
+ "is_valid_rfc3339_date",
93
+ "is_valid_rfc3339_time",
90
94
  "AfdataHandler",
91
95
  "init_logging_json",
92
96
  "init_logging_plain",
@@ -1,10 +1,10 @@
1
1
  """AFDATA output formatting and protocol templates.
2
2
 
3
- 19 public APIs and 4 types: protocol builders, value redactors (copy and
3
+ 21 public APIs and 4 types: protocol builders, value redactors (copy and
4
4
  in-place; cover _secret and _url fields), output formatters, URL-string
5
5
  redactors (redact_url_secrets / _with_options), parse_size,
6
- normalize_utc_offset, RedactionPolicy, RedactionOptions, OutputStyle, and
7
- OutputOptions.
6
+ normalize_utc_offset, is_valid_rfc3339_date, is_valid_rfc3339_time,
7
+ RedactionPolicy, RedactionOptions, OutputStyle, and OutputOptions.
8
8
  """
9
9
 
10
10
  from __future__ import annotations
@@ -293,6 +293,38 @@ def normalize_utc_offset(value: str) -> str | None:
293
293
  return f"{s[0]}{hours:02d}:{minutes:02d}"
294
294
 
295
295
 
296
+ def is_valid_rfc3339_date(value: str) -> bool:
297
+ """Return true when value is an RFC 3339 full-date (YYYY-MM-DD)."""
298
+ if not isinstance(value, str):
299
+ return False
300
+ if len(value) != 10 or value[4] != "-" or value[7] != "-":
301
+ return False
302
+ year = _parse_ascii_int(value[0:4])
303
+ month = _parse_ascii_int(value[5:7])
304
+ day = _parse_ascii_int(value[8:10])
305
+ if year is None or month is None or day is None:
306
+ return False
307
+ return 1 <= month <= 12 and 1 <= day <= _days_in_month(year, month)
308
+
309
+
310
+ def is_valid_rfc3339_time(value: str) -> bool:
311
+ """Return true when value is an RFC 3339 partial-time (HH:MM:SS[.fraction])."""
312
+ if not isinstance(value, str):
313
+ return False
314
+ if len(value) < 8 or value[2] != ":" or value[5] != ":":
315
+ return False
316
+ hour = _parse_ascii_int(value[0:2])
317
+ minute = _parse_ascii_int(value[3:5])
318
+ second = _parse_ascii_int(value[6:8])
319
+ if hour is None or minute is None or second is None:
320
+ return False
321
+ if hour > 23 or minute > 59 or second > 59:
322
+ return False
323
+ if len(value) == 8:
324
+ return True
325
+ return value[8] == "." and len(value) > 9 and value[9:].isdigit()
326
+
327
+
296
328
  def _parse_utc_offset_body(body: str) -> tuple[int, int] | None:
297
329
  if not body:
298
330
  return None
@@ -315,6 +347,26 @@ def _parse_utc_offset_body(body: str) -> tuple[int, int] | None:
315
347
  return None
316
348
 
317
349
 
350
+ def _parse_ascii_int(value: str) -> int | None:
351
+ if not value or not (value.isascii() and value.isdigit()):
352
+ return None
353
+ return int(value)
354
+
355
+
356
+ def _days_in_month(year: int, month: int) -> int:
357
+ if month in (1, 3, 5, 7, 8, 10, 12):
358
+ return 31
359
+ if month in (4, 6, 9, 11):
360
+ return 30
361
+ if month == 2:
362
+ return 29 if _is_leap_year(year) else 28
363
+ return 0
364
+
365
+
366
+ def _is_leap_year(year: int) -> bool:
367
+ return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
368
+
369
+
318
370
  # ═══════════════════════════════════════════
319
371
  # Secret Redaction
320
372
  # ═══════════════════════════════════════════
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-first-data
3
- Version: 0.13.1
3
+ Version: 0.13.2
4
4
  Summary: A naming convention that lets AI agents understand your data without being told what it means.
5
5
  License-Expression: MIT
6
6
  Project-URL: Repository, https://github.com/agentfirstkit/agent-first-data
@@ -29,7 +29,7 @@ print(output_json(value))
29
29
  print(output_plain(value))
30
30
  ```
31
31
 
32
- Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, and `cli_handle_version_or_continue`.
32
+ Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, and `cli_handle_version_or_continue`.
33
33
 
34
34
  Logging is available through `init_logging_json`, `init_logging_plain`, `init_logging_yaml`, `span`, and `get_logger`.
35
35
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agent-first-data"
3
- version = "0.13.1"
3
+ version = "0.13.2"
4
4
  description = "A naming convention that lets AI agents understand your data without being told what it means."
5
5
  license = "MIT"
6
6
  readme = "README.md"
@@ -25,6 +25,8 @@ from agent_first_data import (
25
25
  output_plain,
26
26
  output_plain_with_options,
27
27
  normalize_utc_offset,
28
+ is_valid_rfc3339_date,
29
+ is_valid_rfc3339_time,
28
30
  )
29
31
  from agent_first_data.format import (
30
32
  _format_bytes_human,
@@ -149,6 +151,12 @@ def test_helper_fixtures():
149
151
  elif name == "normalize_utc_offset":
150
152
  got = normalize_utc_offset(inp)
151
153
  assert got == expected, f"[helpers/{name}({inp!r})] got {got!r}"
154
+ elif name == "is_valid_rfc3339_date":
155
+ got = is_valid_rfc3339_date(inp)
156
+ assert got == expected, f"[helpers/{name}({inp!r})] got {got!r}"
157
+ elif name == "is_valid_rfc3339_time":
158
+ got = is_valid_rfc3339_time(inp)
159
+ assert got == expected, f"[helpers/{name}({inp!r})] got {got!r}"
152
160
 
153
161
 
154
162
  def test_output_format_fixtures():