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