fix: parse compact ISO 8601 date/datetime string formats#289
fix: parse compact ISO 8601 date/datetime string formats#289DecisionNerd merged 2 commits intomainfrom
Conversation
Adds _parse_iso_date_part() and _normalize_compact_time() helpers in types/values.py to handle compact ISO 8601 variants not supported by dateutil: ordinal (YYYY-DDD, YYYYDDD), week (YYYY-Www[-D], YYYYWww[D]), year-month (YYYY-MM, YYYYMM), and year-only (YYYY). CypherDate now uses _parse_iso_date_part() instead of dateutil directly. CypherDateTime splits on 'T', normalises each part, then re-assembles before passing to dateutil, handling compact date and time components. Fixes 14 TCK failures in should_parse_date_from_string and should_parse_local_date_time_from_string. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughThis PR adds support for compact ISO 8601 date/datetime string formats (ordinal, week-based, year-month, year-only, compact time) by introducing helper functions Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
tests/integration/test_compact_iso8601.py (1)
12-99: Parametrize repeated cases to reduce duplication.Line 12 onward repeats the same test flow with only input/expected values changing. Converting both classes to
@pytest.mark.parametrizewould keep coverage while reducing maintenance overhead.♻️ Example refactor pattern
+@pytest.mark.parametrize( + ("expr", "alias", "expected"), + [ + ("date('2015')", "d", "2015-01-01"), + ("date('2015-07')", "d", "2015-07-01"), + ("date('201507')", "d", "2015-07-01"), + ("date('2015-202')", "d", "2015-07-21"), + ("date('2015202')", "d", "2015-07-21"), + ("date('2015-W30-2')", "d", "2015-07-21"), + ("date('2015W302')", "d", "2015-07-21"), + ("date('2015-W30')", "d", "2015-07-20"), + ("date('2015W30')", "d", "2015-07-20"), + ], +) +def test_compact_iso8601_date_cases(expr, alias, expected): + gf = GraphForge() + r = gf.execute(f"RETURN {expr} AS {alias}") + assert r[0][alias].value.isoformat() == expectedAs per coding guidelines: "Use
@pytest.mark.parametrizefor testing the same logic with different inputs to avoid code duplication".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/integration/test_compact_iso8601.py` around lines 12 - 99, Multiple test methods in TestCompactISO8601 and TestCompactISO8601LocalDateTime duplicate the same pattern; replace them with parametrized tests using `@pytest.mark.parametrize` to supply (input_string, expected_iso) pairs and a single test function that creates GraphForge, calls gf.execute("RETURN date(...)"/"RETURN localdatetime(...)") and asserts r[0][...].value.isoformat() == expected_iso; target the classes TestCompactISO8601 and TestCompactISO8601LocalDateTime and consolidate the current test_* methods (e.g., test_year_only, test_year_month_separator, test_year_month_compact, test_ordinal_separator, test_ordinal_compact, test_week_date_with_day_separator, test_week_date_with_day_compact, test_week_date_no_day_separator, test_week_date_no_day_compact and the localdatetime variants) into two parametrized test functions while keeping `@pytest.mark.integration` on the classes or tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/graphforge/types/values.py`:
- Around line 332-339: The code allows unsupported compact-time lengths to
silently pass through by returning t + frac + tz; instead, detect any unexpected
length of the compact time string (variable t) and raise a clear ValueError
describing the offending input and its length so malformed inputs fail fast.
Replace the final fallback return with raising ValueError(f"unsupported compact
time length {len(t)} for input: {t}") (and keep the existing branches for
lengths 2, 4, 6 intact); update any callers/tests to expect the exception where
appropriate.
- Around line 276-285: The ordinal-date parsing blocks that match
r"^(\d{4})-(\d{3})$" and r"^(\d{4})(\d{3})$" must validate the extracted ordinal
before adding days; after extracting year = int(m.group(1)) and ordinal =
int(m.group(2)), compute the year's max ordinal (use 365/366 via
calendar.isleap(year) or equivalent) and if ordinal < 1 or ordinal > max_ordinal
raise a ValueError (or return an error) instead of blindly doing
datetime.date(year,1,1) + datetime.timedelta(...); only perform the date
arithmetic when the ordinal is in-range.
---
Nitpick comments:
In `@tests/integration/test_compact_iso8601.py`:
- Around line 12-99: Multiple test methods in TestCompactISO8601 and
TestCompactISO8601LocalDateTime duplicate the same pattern; replace them with
parametrized tests using `@pytest.mark.parametrize` to supply (input_string,
expected_iso) pairs and a single test function that creates GraphForge, calls
gf.execute("RETURN date(...)"/"RETURN localdatetime(...)") and asserts
r[0][...].value.isoformat() == expected_iso; target the classes
TestCompactISO8601 and TestCompactISO8601LocalDateTime and consolidate the
current test_* methods (e.g., test_year_only, test_year_month_separator,
test_year_month_compact, test_ordinal_separator, test_ordinal_compact,
test_week_date_with_day_separator, test_week_date_with_day_compact,
test_week_date_no_day_separator, test_week_date_no_day_compact and the
localdatetime variants) into two parametrized test functions while keeping
`@pytest.mark.integration` on the classes or tests.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #289 +/- ##
==========================================
+ Coverage 90.00% 90.04% +0.03%
==========================================
Files 38 38
Lines 10379 10495 +116
Branches 2130 2149 +19
==========================================
+ Hits 9342 9450 +108
Misses 728 728
- Partials 309 317 +8
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Sentry.
|
- _parse_iso_date_part: validate ordinal day is in range [1, 365/366] before constructing date; raises ValueError for out-of-range values instead of silently rolling into adjacent years - _normalize_compact_time: raise ValueError for unexpected compact time digit lengths (not 2, 4, or 6) instead of passing through to dateutil - Add 4 validation tests covering both error paths and leap year edge case Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Closes #273
Summary
_parse_iso_date_part(s)helper handling all compact ISO 8601 date forms: ordinal (YYYY-DDD,YYYYDDD), week date (YYYY-Www[-D],YYYYWww[D]), year-month (YYYY-MM,YYYYMM), and year-only (YYYY)_normalize_compact_time(t)helper expanding compact time strings (HH,HHMM,HHMMSS) toHH:MM:SSform (with optional fractional seconds and timezone passthrough)CypherDate.__init__to use_parse_iso_date_partinstead of dateutil directlyCypherDateTime.__init__to split onT, normalise date and time parts independently, then re-assemble before passing to dateutilFixes
14 TCK failures in
should_parse_date_from_stringandshould_parse_local_date_time_from_string.Test plan
TestCompactISO8601Date)TestCompactISO8601LocalDateTime)make pre-pushgreen🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests