ltc-code 0.1.92__tar.gz → 0.1.93__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.
- {ltc_code-0.1.92 → ltc_code-0.1.93}/PKG-INFO +1 -1
- {ltc_code-0.1.92 → ltc_code-0.1.93}/pyproject.toml +1 -1
- {ltc_code-0.1.92 → ltc_code-0.1.93}/src/ltc_code/june7.py +137 -51
- {ltc_code-0.1.92 → ltc_code-0.1.93}/README.md +0 -0
- {ltc_code-0.1.92 → ltc_code-0.1.93}/src/ltc_code/__init__.py +0 -0
- {ltc_code-0.1.92 → ltc_code-0.1.93}/src/ltc_code/green_dot.py +0 -0
- {ltc_code-0.1.92 → ltc_code-0.1.93}/src/ltc_code/june2.py +0 -0
- {ltc_code-0.1.92 → ltc_code-0.1.93}/src/ltc_code/june5.py +0 -0
- {ltc_code-0.1.92 → ltc_code-0.1.93}/src/ltc_code/kipp_nj.py +0 -0
- {ltc_code-0.1.92 → ltc_code-0.1.93}/src/ltc_code/kipp_tx.py +0 -0
- {ltc_code-0.1.92 → ltc_code-0.1.93}/src/ltc_code/may27.py +0 -0
- {ltc_code-0.1.92 → ltc_code-0.1.93}/src/ltc_code/polars_dates.py +0 -0
- {ltc_code-0.1.92 → ltc_code-0.1.93}/src/ltc_code/schema_mapping.py +0 -0
|
@@ -413,16 +413,19 @@ final = df.pipe(
|
|
|
413
413
|
|
|
414
414
|
|
|
415
415
|
|
|
416
|
+
import re
|
|
416
417
|
from typing import Mapping, Optional, Sequence, Union
|
|
417
418
|
|
|
418
419
|
import polars as pl
|
|
419
420
|
|
|
420
421
|
|
|
421
|
-
|
|
422
|
-
"
|
|
423
|
-
|
|
422
|
+
PRIORITY_PATTERNS_BY_CMO = {
|
|
423
|
+
"yes_prep": {
|
|
424
|
+
# Patterns used to create broad 1/0 priority flags.
|
|
425
|
+
"concept_patterns": {
|
|
424
426
|
"sibling": [
|
|
425
427
|
r"\bsibling\s+attending\b",
|
|
428
|
+
r"\bdynamic\s+sa\b",
|
|
426
429
|
],
|
|
427
430
|
"staff": [
|
|
428
431
|
r"\bemployee\b",
|
|
@@ -430,46 +433,95 @@ DEFAULT_PRIORITY_PATTERNS_BY_CMO = {
|
|
|
430
433
|
"zoned": [
|
|
431
434
|
r"\bisd\b",
|
|
432
435
|
r"\bzoned\s+for\b",
|
|
433
|
-
r"\bdynamic\s+sa\b",
|
|
434
436
|
],
|
|
435
437
|
"transfer": [
|
|
436
|
-
r"
|
|
438
|
+
r"\btransfer\b",
|
|
437
439
|
],
|
|
438
440
|
},
|
|
439
|
-
|
|
440
|
-
|
|
441
|
+
|
|
442
|
+
# Patterns used to flag repeated concepts.
|
|
443
|
+
# Example: "Sibling Attending - Sibling Attending Ben Holt"
|
|
444
|
+
# gives sibling_repeat = 1.
|
|
445
|
+
"repeat_patterns": {
|
|
446
|
+
"sibling_repeat": [
|
|
441
447
|
r"\bsibling\s+attending\b",
|
|
448
|
+
r"\bdynamic\s+sa\b",
|
|
442
449
|
],
|
|
443
450
|
"zoned_repeat": [
|
|
444
451
|
r"\bzoned\s+for\b",
|
|
445
452
|
],
|
|
453
|
+
"transfer_repeat": [
|
|
454
|
+
r"\btransfer\b",
|
|
455
|
+
],
|
|
456
|
+
},
|
|
457
|
+
|
|
458
|
+
# Patterns used to normalize each dash/plus-separated component.
|
|
459
|
+
# Anything unmatched is preserved as lowercased text.
|
|
460
|
+
"component_replacements": {
|
|
461
|
+
"sibling": [
|
|
462
|
+
r"\bsibling\s+attending(?:\s+.+)?\b",
|
|
463
|
+
r"\bdynamic\s+sa\b",
|
|
464
|
+
],
|
|
465
|
+
"staff": [
|
|
466
|
+
r"\bemployee\b",
|
|
467
|
+
],
|
|
468
|
+
"zoned": [
|
|
469
|
+
r"\bisd\b",
|
|
470
|
+
r"\bzoned\s+for\s+.+\b",
|
|
471
|
+
],
|
|
472
|
+
"transfer": [
|
|
473
|
+
r"\btransfer\b",
|
|
474
|
+
],
|
|
446
475
|
},
|
|
447
476
|
},
|
|
448
477
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
"flags": {
|
|
478
|
+
"aspire": {
|
|
479
|
+
"concept_patterns": {
|
|
452
480
|
"sibling": [
|
|
453
481
|
r"\bsibling\s+attending\b",
|
|
482
|
+
r"\bmultiples\b",
|
|
483
|
+
r"\bmutiples\b",
|
|
454
484
|
],
|
|
455
485
|
"staff": [
|
|
456
486
|
r"\bemployee\b",
|
|
457
487
|
],
|
|
458
488
|
"zoned": [
|
|
459
|
-
r"\
|
|
460
|
-
r"\bzoned\s+for\b",
|
|
461
|
-
r"\bdynamic\s+sa\b",
|
|
489
|
+
r"\bin\s+district\b",
|
|
462
490
|
],
|
|
463
491
|
"transfer": [
|
|
464
|
-
r"
|
|
492
|
+
r"\btransfer\b",
|
|
465
493
|
],
|
|
466
494
|
},
|
|
467
|
-
|
|
468
|
-
|
|
495
|
+
|
|
496
|
+
"repeat_patterns": {
|
|
497
|
+
"sibling_repeat": [
|
|
469
498
|
r"\bsibling\s+attending\b",
|
|
499
|
+
r"\bmultiples\b",
|
|
500
|
+
r"\bmutiples\b",
|
|
501
|
+
],
|
|
502
|
+
"transfer_repeat": [
|
|
503
|
+
r"\btransfer\b",
|
|
470
504
|
],
|
|
471
505
|
"zoned_repeat": [
|
|
472
|
-
r"\
|
|
506
|
+
r"\bin\s+district\b",
|
|
507
|
+
],
|
|
508
|
+
},
|
|
509
|
+
|
|
510
|
+
"component_replacements": {
|
|
511
|
+
"sibling": [
|
|
512
|
+
r"\bsibling\s+attending(?:\s+.+)?\b",
|
|
513
|
+
r"\bmultiples\b",
|
|
514
|
+
r"\bmutiples\b",
|
|
515
|
+
],
|
|
516
|
+
"staff": [
|
|
517
|
+
r"\bemployee\b",
|
|
518
|
+
],
|
|
519
|
+
"zoned": [
|
|
520
|
+
r"\bin\s+district\b",
|
|
521
|
+
],
|
|
522
|
+
"transfer": [
|
|
523
|
+
r"\b(?:intra\s+)?aspire\s+transfer(?::?\s+.+)?\b",
|
|
524
|
+
r"\btransfer(?::?\s+.+)?\b",
|
|
473
525
|
],
|
|
474
526
|
},
|
|
475
527
|
},
|
|
@@ -479,22 +531,11 @@ DEFAULT_PRIORITY_PATTERNS_BY_CMO = {
|
|
|
479
531
|
def add_priority_flags(
|
|
480
532
|
df: Union[pl.DataFrame, pl.LazyFrame],
|
|
481
533
|
priority_col: str,
|
|
482
|
-
cmo: str
|
|
534
|
+
cmo: str,
|
|
483
535
|
patterns_by_cmo: Optional[Mapping[str, Mapping[str, Mapping[str, Sequence[str]]]]] = None,
|
|
536
|
+
cleaned_col: str = "priority_group_clean",
|
|
484
537
|
) -> Union[pl.DataFrame, pl.LazyFrame]:
|
|
485
|
-
"""Create priority flags
|
|
486
|
-
|
|
487
|
-
Adds:
|
|
488
|
-
sibling
|
|
489
|
-
staff
|
|
490
|
-
zoned
|
|
491
|
-
transfer
|
|
492
|
-
sib_repeat
|
|
493
|
-
zoned_repeat
|
|
494
|
-
|
|
495
|
-
The helper lowercases the priority string and normalizes dashes/pluses to
|
|
496
|
-
spaces before matching regex patterns.
|
|
497
|
-
"""
|
|
538
|
+
"""Create broad priority flags and a normalized priority string."""
|
|
498
539
|
if not isinstance(df, (pl.DataFrame, pl.LazyFrame)):
|
|
499
540
|
raise TypeError("df must be a polars DataFrame or LazyFrame.")
|
|
500
541
|
|
|
@@ -502,7 +543,7 @@ def add_priority_flags(
|
|
|
502
543
|
if priority_col not in columns:
|
|
503
544
|
raise ValueError("Missing priority column: %s" % priority_col)
|
|
504
545
|
|
|
505
|
-
patterns_by_cmo = patterns_by_cmo or
|
|
546
|
+
patterns_by_cmo = patterns_by_cmo or PRIORITY_PATTERNS_BY_CMO
|
|
506
547
|
if cmo not in patterns_by_cmo:
|
|
507
548
|
raise ValueError(
|
|
508
549
|
"No priority pattern mapping found for cmo=%r. Available CMOs: %s"
|
|
@@ -510,56 +551,101 @@ def add_priority_flags(
|
|
|
510
551
|
)
|
|
511
552
|
|
|
512
553
|
config = patterns_by_cmo[cmo]
|
|
513
|
-
|
|
514
|
-
repeat_patterns = config.get("
|
|
554
|
+
concept_patterns = config.get("concept_patterns", {})
|
|
555
|
+
repeat_patterns = config.get("repeat_patterns", {})
|
|
556
|
+
component_replacements = config.get("component_replacements", {})
|
|
515
557
|
|
|
516
|
-
def
|
|
517
|
-
|
|
558
|
+
def _contains_any(patterns: Sequence[str]) -> pl.Expr:
|
|
559
|
+
if not patterns:
|
|
560
|
+
return pl.lit(False)
|
|
561
|
+
return pl.any_horizontal(
|
|
562
|
+
[pl.col("_priority_text").str.contains(pattern) for pattern in patterns]
|
|
563
|
+
)
|
|
518
564
|
|
|
519
|
-
def
|
|
565
|
+
def _count_any(patterns: Sequence[str]) -> pl.Expr:
|
|
520
566
|
if not patterns:
|
|
521
567
|
return pl.lit(0)
|
|
522
568
|
return pl.sum_horizontal(
|
|
523
|
-
[
|
|
524
|
-
pl.col("_priority_text").str.count_matches(pattern)
|
|
525
|
-
for pattern in patterns
|
|
526
|
-
]
|
|
569
|
+
[pl.col("_priority_text").str.count_matches(pattern) for pattern in patterns]
|
|
527
570
|
)
|
|
528
571
|
|
|
572
|
+
def _clean_component(value: object) -> Optional[str]:
|
|
573
|
+
if value is None:
|
|
574
|
+
return None
|
|
575
|
+
|
|
576
|
+
text = str(value).strip().lower()
|
|
577
|
+
if not text:
|
|
578
|
+
return None
|
|
579
|
+
|
|
580
|
+
text = re.sub(r"\s+", " ", text)
|
|
581
|
+
|
|
582
|
+
for clean_label, patterns in component_replacements.items():
|
|
583
|
+
for pattern in patterns:
|
|
584
|
+
if re.search(pattern, text):
|
|
585
|
+
return clean_label
|
|
586
|
+
|
|
587
|
+
return text
|
|
588
|
+
|
|
589
|
+
def _normalize_priority(value: object) -> Optional[str]:
|
|
590
|
+
if value is None:
|
|
591
|
+
return None
|
|
592
|
+
|
|
593
|
+
text = str(value).lower()
|
|
594
|
+
text = re.sub(r"[-+]", "|", text)
|
|
595
|
+
raw_parts = [part.strip() for part in text.split("|")]
|
|
596
|
+
|
|
597
|
+
cleaned_parts = []
|
|
598
|
+
seen = set()
|
|
599
|
+
for part in raw_parts:
|
|
600
|
+
cleaned = _clean_component(part)
|
|
601
|
+
if cleaned is None or cleaned in seen:
|
|
602
|
+
continue
|
|
603
|
+
cleaned_parts.append(cleaned)
|
|
604
|
+
seen.add(cleaned)
|
|
605
|
+
|
|
606
|
+
if not cleaned_parts:
|
|
607
|
+
return None
|
|
608
|
+
|
|
609
|
+
return " - ".join(sorted(cleaned_parts))
|
|
610
|
+
|
|
529
611
|
result = df.with_columns(
|
|
530
612
|
pl.col(priority_col)
|
|
531
613
|
.cast(pl.Utf8, strict=False)
|
|
532
614
|
.fill_null("")
|
|
533
615
|
.str.to_lowercase()
|
|
534
|
-
.str.replace_all(r"[-+]", " ")
|
|
535
616
|
.alias("_priority_text")
|
|
536
617
|
)
|
|
537
618
|
|
|
538
619
|
result = result.with_columns(
|
|
539
620
|
[
|
|
540
|
-
pl.
|
|
541
|
-
.
|
|
542
|
-
.cast(pl.Int8)
|
|
543
|
-
.alias(flag_name)
|
|
544
|
-
for flag_name, patterns in flag_patterns.items()
|
|
621
|
+
_contains_any(patterns).cast(pl.Int8).alias(flag_name)
|
|
622
|
+
for flag_name, patterns in concept_patterns.items()
|
|
545
623
|
]
|
|
546
624
|
)
|
|
547
625
|
|
|
548
626
|
result = result.with_columns(
|
|
549
627
|
[
|
|
550
|
-
(
|
|
551
|
-
.cast(pl.Int8)
|
|
552
|
-
.alias(flag_name)
|
|
628
|
+
(_count_any(patterns) > 1).cast(pl.Int8).alias(flag_name)
|
|
553
629
|
for flag_name, patterns in repeat_patterns.items()
|
|
554
630
|
]
|
|
555
631
|
)
|
|
556
632
|
|
|
557
|
-
|
|
633
|
+
result = result.with_columns(
|
|
634
|
+
pl.col(priority_col)
|
|
635
|
+
.map_elements(_normalize_priority, return_dtype=pl.Utf8)
|
|
636
|
+
.alias(cleaned_col)
|
|
637
|
+
)
|
|
558
638
|
|
|
639
|
+
return result.drop("_priority_text")
|
|
559
640
|
|
|
560
641
|
|
|
561
642
|
df = df.pipe(
|
|
562
643
|
add_priority_flags,
|
|
563
644
|
priority_col="priority_group_name",
|
|
564
645
|
cmo="yes_prep",
|
|
646
|
+
)
|
|
647
|
+
df = df.pipe(
|
|
648
|
+
add_priority_flags,
|
|
649
|
+
priority_col="priority_group_name",
|
|
650
|
+
cmo="aspire",
|
|
565
651
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|