umt-python 0.2.0__py3-none-any.whl → 0.4.0__py3-none-any.whl

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.
umt_python/__init__.py CHANGED
@@ -1,3 +1,6 @@
1
+ from .advance import (
2
+ range_advance,
3
+ )
1
4
  from .array import (
2
5
  ValidatedSortRange,
3
6
  apply_insertion_sort_if_needed,
@@ -33,6 +36,21 @@ from .array import (
33
36
  zip_arrays,
34
37
  zip_longest,
35
38
  )
39
+ from .async_util import (
40
+ AbortSignal,
41
+ DebouncedAsyncFunction,
42
+ Deferred,
43
+ SettledResult,
44
+ ThrottledAsyncFunction,
45
+ debounce_async,
46
+ defer,
47
+ p_settled,
48
+ parallel,
49
+ sleep,
50
+ throttle_async,
51
+ timeout,
52
+ wait_for,
53
+ )
36
54
  from .color import (
37
55
  cmyk_to_rgba,
38
56
  hexa_to_rgba,
@@ -57,6 +75,7 @@ from .consts import (
57
75
  HttpInformationalStatus,
58
76
  HttpRedirectionStatus,
59
77
  HttpServerErrorStatus,
78
+ HttpStatus,
60
79
  HttpSuccessStatus,
61
80
  )
62
81
  from .crypto import (
@@ -68,30 +87,64 @@ from .crypto import (
68
87
  encode_base58,
69
88
  )
70
89
  from .data_structure import (
90
+ LRUCache,
71
91
  PriorityQueue,
92
+ TTLCache,
72
93
  )
73
94
  from .date import (
74
95
  DAY_LIST,
96
+ DateInclusivity,
97
+ UnixTimeUnit,
98
+ add_business_days,
99
+ add_duration,
75
100
  birthday,
76
101
  date_format,
77
102
  date_now,
78
103
  date_range,
79
104
  day_of_week,
105
+ diff,
106
+ end_of,
107
+ format_relative,
108
+ from_unix,
80
109
  get_day,
110
+ get_quarter,
81
111
  get_timezone_offset_string,
112
+ is_between,
113
+ is_business_day,
82
114
  is_leap_year,
115
+ is_same_day,
116
+ is_weekend,
117
+ ms_by_unit,
83
118
  new_date_int,
84
119
  new_date_string,
120
+ start_of,
121
+ sub_business_days,
122
+ sub_duration,
123
+ to_unix,
124
+ week_of_year,
85
125
  )
86
126
  from .error import (
87
127
  Error,
88
128
  Result,
89
129
  Success,
130
+ error_function,
131
+ flat_map_result,
132
+ map_result,
133
+ match_result,
90
134
  retry,
91
135
  safe_execute,
136
+ success_function,
92
137
  )
93
138
  from .function import (
139
+ DebouncedFunction,
140
+ MemoizedFunction,
141
+ OnceFunction,
142
+ ThrottledFunction,
94
143
  curry,
144
+ debounce,
145
+ memoize,
146
+ once,
147
+ throttle,
95
148
  )
96
149
  from .ip import (
97
150
  cidr_to_long,
@@ -110,6 +163,10 @@ from .iterator import (
110
163
  lazy_map,
111
164
  lazy_take,
112
165
  )
166
+ from .map import (
167
+ group_by_to_map,
168
+ zip_to_map,
169
+ )
113
170
  from .math import (
114
171
  PrimeFactor,
115
172
  ProbabilityFraction,
@@ -117,6 +174,11 @@ from .math import (
117
174
  addition,
118
175
  average,
119
176
  bitwise,
177
+ calculator,
178
+ calculator_core,
179
+ calculator_initialization,
180
+ clamp,
181
+ convert_currency,
120
182
  correlation_coefficient,
121
183
  deg_to_rad,
122
184
  deviation_value,
@@ -126,11 +188,13 @@ from .math import (
126
188
  flexible_number_conversion,
127
189
  gcd,
128
190
  get_decimal_length,
191
+ in_range,
129
192
  is_double,
130
193
  is_perfect_square,
131
194
  is_prime_number,
132
195
  lcm,
133
196
  linear_congruential_generator,
197
+ literal_expression,
134
198
  math_converter,
135
199
  math_separator,
136
200
  max_value,
@@ -153,26 +217,66 @@ from .math import (
153
217
  solve_equation,
154
218
  standard_deviation,
155
219
  subtraction,
220
+ sum_precise,
156
221
  to_base_n,
157
222
  uuidv7,
158
223
  value_swap,
159
224
  xoshiro256,
160
225
  )
161
226
  from .number import (
227
+ format_number,
162
228
  to_ordinal,
229
+ to_percentage,
163
230
  )
164
231
  from .object import (
232
+ deep_clone,
233
+ flatten_object,
234
+ get_objects_common,
235
+ get_objects_diff,
236
+ invert,
237
+ map_keys,
238
+ object_get,
165
239
  object_has,
166
240
  object_is_empty,
241
+ object_is_plain,
242
+ object_key_by,
167
243
  object_map_values,
168
244
  object_merge,
169
245
  object_merge_deep,
170
246
  object_omit,
171
247
  object_pick,
172
248
  object_pick_deep,
249
+ object_set,
250
+ omit_by,
251
+ path_segments,
252
+ pick_by,
253
+ remove_prototype,
254
+ remove_prototype_deep,
255
+ remove_prototype_map,
256
+ remove_prototype_map_deep,
257
+ unflatten_object,
173
258
  )
174
259
  from .predicate import (
175
260
  every,
261
+ is_not_nullish,
262
+ is_nullish,
263
+ matches,
264
+ not_,
265
+ some,
266
+ )
267
+ from .random import (
268
+ WeightedItem,
269
+ random_boolean,
270
+ random_choice,
271
+ random_float,
272
+ random_uuid,
273
+ seeded_random,
274
+ weighted_choice,
275
+ )
276
+ from .simple.date import (
277
+ birthday_simple,
278
+ day_of_week_simple,
279
+ now_simple,
176
280
  )
177
281
  from .simple.math import (
178
282
  deviation_value_simple,
@@ -181,30 +285,60 @@ from .string import (
181
285
  DEFAULT_RANDOM_STRING_CHARS,
182
286
  HTML_ESCAPE_MAP,
183
287
  HTML_UNESCAPE_MAP,
288
+ Formatter,
184
289
  FuzzySearchResult,
290
+ apply_formatter,
185
291
  camel_case,
292
+ capitalize,
293
+ capitalize_word,
294
+ constant_case,
295
+ count_occurrences,
296
+ deburr,
297
+ dedent,
298
+ default_formatters,
186
299
  delete_spaces,
300
+ detect_mode,
301
+ ensure_prefix,
302
+ ensure_suffix,
187
303
  escape_html,
188
304
  format_string,
189
305
  from_base64,
190
306
  fuzzy_search,
307
+ get_value,
191
308
  has_no_letters,
309
+ js_string,
192
310
  kebab_case,
193
311
  levenshtein_distance,
312
+ mask,
313
+ normalize_whitespace,
194
314
  pad_end,
195
315
  pad_start,
316
+ pascal_case,
196
317
  random_string,
197
318
  random_string_initialization,
319
+ remove_prefix,
320
+ remove_suffix,
198
321
  reverse_string,
322
+ sanitize_string,
199
323
  slugify,
324
+ snake_case,
325
+ split_by_length,
200
326
  string_similarity,
327
+ strip_ansi,
328
+ strip_tags,
329
+ swap_case,
330
+ title_case,
201
331
  to_base64,
332
+ to_full_width,
202
333
  to_half_width,
203
334
  trim_characters,
204
335
  trim_end_characters,
205
336
  trim_start_characters,
206
337
  truncate,
338
+ uncapitalize,
207
339
  unescape_html,
340
+ word_count,
341
+ words,
208
342
  )
209
343
  from .time import (
210
344
  convert_time,
@@ -214,8 +348,10 @@ from .tool import (
214
348
  Pipe,
215
349
  Pipeline,
216
350
  create_pipeline,
351
+ escape_regexp,
217
352
  parse_json,
218
353
  pipe,
354
+ unwrap,
219
355
  )
220
356
  from .ua import (
221
357
  extract_browser_from_user_agent,
@@ -229,24 +365,64 @@ from .unit import (
229
365
  unit_converter_initialization,
230
366
  )
231
367
  from .url import (
368
+ build_url,
232
369
  is_absolute_url,
233
370
  join_path,
371
+ parse_query_string,
234
372
  )
235
373
  from .validate import (
374
+ AnyReturnType,
375
+ ArrayOfReturnType,
376
+ BigIntReturnType,
377
+ BigIntRule,
378
+ DateReturnType,
236
379
  EmailParts,
380
+ FileReturnType,
381
+ FunctionReturnType,
382
+ FunctionSchema,
383
+ FunctionValidator,
384
+ InstanceOfReturnType,
237
385
  IsDeepEqualOptions,
386
+ MapReturnType,
387
+ NeverReturnType,
388
+ NumberReturnType,
389
+ NumberRule,
238
390
  ParseEmailLevel,
239
391
  ParseEmailOptions,
240
392
  ParseEmailResult,
393
+ SetOfReturnType,
394
+ StringReturnType,
395
+ StringRule,
396
+ TemplateLiteralReturnType,
397
+ UnknownReturnType,
398
+ any_validator,
399
+ array_of,
400
+ bigint,
401
+ date,
402
+ file,
403
+ func,
404
+ instance_of,
241
405
  is_array,
406
+ is_boolean,
407
+ is_browser,
408
+ is_bun,
242
409
  is_deep_equal,
243
410
  is_dictionary_object,
244
411
  is_equal,
412
+ is_node,
413
+ is_node_webkit,
245
414
  is_not_empty,
246
415
  is_number,
247
416
  is_string,
248
417
  is_value_nan,
418
+ map_validator,
419
+ never_validator,
420
+ number,
249
421
  parse_email,
422
+ set_of,
423
+ string,
424
+ template_literal,
425
+ unknown_validator,
250
426
  )
251
427
 
252
428
  __all__ = [
@@ -265,15 +441,39 @@ __all__ = [
265
441
  "ONE_WEEK_MS",
266
442
  "ONE_YEAR_MS",
267
443
  "ONE_YEAR_MS_366",
444
+ "AbortSignal",
445
+ "AnyReturnType",
446
+ "ArrayOfReturnType",
447
+ "BigIntReturnType",
448
+ "BigIntRule",
449
+ "DateInclusivity",
450
+ "DateReturnType",
451
+ "DebouncedAsyncFunction",
452
+ "DebouncedFunction",
453
+ "Deferred",
268
454
  "EmailParts",
269
455
  "Error",
456
+ "FileReturnType",
457
+ "Formatter",
458
+ "FunctionReturnType",
459
+ "FunctionSchema",
460
+ "FunctionValidator",
270
461
  "FuzzySearchResult",
271
462
  "HttpClientErrorStatus",
272
463
  "HttpInformationalStatus",
273
464
  "HttpRedirectionStatus",
274
465
  "HttpServerErrorStatus",
466
+ "HttpStatus",
275
467
  "HttpSuccessStatus",
468
+ "InstanceOfReturnType",
276
469
  "IsDeepEqualOptions",
470
+ "LRUCache",
471
+ "MapReturnType",
472
+ "MemoizedFunction",
473
+ "NeverReturnType",
474
+ "NumberReturnType",
475
+ "NumberRule",
476
+ "OnceFunction",
277
477
  "ParseEmailLevel",
278
478
  "ParseEmailOptions",
279
479
  "ParseEmailResult",
@@ -284,56 +484,107 @@ __all__ = [
284
484
  "ProbabilityFraction",
285
485
  "ReducedFraction",
286
486
  "Result",
487
+ "SetOfReturnType",
488
+ "SettledResult",
489
+ "StringReturnType",
490
+ "StringRule",
287
491
  "Success",
492
+ "TTLCache",
493
+ "TemplateLiteralReturnType",
494
+ "ThrottledAsyncFunction",
495
+ "ThrottledFunction",
496
+ "UnixTimeUnit",
497
+ "UnknownReturnType",
288
498
  "ValidatedSortRange",
499
+ "WeightedItem",
500
+ "add_business_days",
501
+ "add_duration",
289
502
  "addition",
503
+ "any_validator",
504
+ "apply_formatter",
290
505
  "apply_insertion_sort_if_needed",
506
+ "array_of",
291
507
  "array_sum",
292
508
  "arrays_join",
293
509
  "average",
510
+ "bigint",
294
511
  "binary_search",
295
512
  "birthday",
513
+ "birthday_simple",
296
514
  "bitwise",
515
+ "build_url",
516
+ "calculator",
517
+ "calculator_core",
518
+ "calculator_initialization",
297
519
  "camel_case",
520
+ "capitalize",
521
+ "capitalize_word",
298
522
  "check_flag_alignment",
299
523
  "chunk",
300
524
  "cidr_to_long",
301
525
  "cidr_to_subnet_mask",
526
+ "clamp",
302
527
  "cmyk_to_rgba",
303
528
  "compact",
304
529
  "compare_function_default",
530
+ "constant_case",
531
+ "convert_currency",
305
532
  "convert_time",
306
533
  "correlation_coefficient",
534
+ "count_occurrences",
307
535
  "create_pipeline",
308
536
  "curry",
537
+ "date",
309
538
  "date_format",
310
539
  "date_now",
311
540
  "date_range",
312
541
  "day_of_week",
542
+ "day_of_week_simple",
543
+ "debounce",
544
+ "debounce_async",
545
+ "deburr",
313
546
  "decode_base32",
314
547
  "decode_base32_to_string",
315
548
  "decode_base58",
316
549
  "decode_base58_to_string",
550
+ "dedent",
551
+ "deep_clone",
552
+ "default_formatters",
553
+ "defer",
317
554
  "deg_to_rad",
318
555
  "delete_spaces",
556
+ "detect_mode",
319
557
  "deviation_value",
320
558
  "deviation_value_simple",
559
+ "diff",
321
560
  "division",
322
561
  "drop",
323
562
  "dual_pivot_quick_sort",
324
563
  "encode_base32",
325
564
  "encode_base58",
565
+ "end_of",
566
+ "ensure_prefix",
567
+ "ensure_suffix",
568
+ "error_function",
326
569
  "escape_html",
570
+ "escape_regexp",
327
571
  "every",
328
572
  "extract_browser_from_user_agent",
329
573
  "extract_device_from_user_agent",
330
574
  "extract_os_from_user_agent",
331
575
  "factorial",
332
576
  "factorize",
577
+ "file",
333
578
  "first",
579
+ "flat_map_result",
580
+ "flatten_object",
334
581
  "flexible_number_conversion",
582
+ "format_number",
583
+ "format_relative",
335
584
  "format_string",
336
585
  "from_base64",
586
+ "from_unix",
587
+ "func",
337
588
  "fuzzy_search",
338
589
  "gcd",
339
590
  "generate_number_array",
@@ -343,31 +594,51 @@ __all__ = [
343
594
  "get_decimal_length",
344
595
  "get_ip_class",
345
596
  "get_network_address",
597
+ "get_objects_common",
598
+ "get_objects_diff",
599
+ "get_quarter",
346
600
  "get_timezone_offset_string",
601
+ "get_value",
347
602
  "group_by",
603
+ "group_by_to_map",
348
604
  "has_no_letters",
349
605
  "hexa_to_rgba",
350
606
  "hsla_to_rgba",
607
+ "in_range",
351
608
  "insertion_sort",
352
609
  "insertion_sort_range",
610
+ "instance_of",
611
+ "invert",
353
612
  "ip_to_binary_string",
354
613
  "ip_to_long",
355
614
  "is_absolute_url",
356
615
  "is_array",
616
+ "is_between",
617
+ "is_boolean",
618
+ "is_browser",
619
+ "is_bun",
620
+ "is_business_day",
357
621
  "is_deep_equal",
358
622
  "is_dictionary_object",
359
623
  "is_double",
360
624
  "is_equal",
361
625
  "is_in_range",
362
626
  "is_leap_year",
627
+ "is_node",
628
+ "is_node_webkit",
363
629
  "is_not_empty",
630
+ "is_not_nullish",
631
+ "is_nullish",
364
632
  "is_number",
365
633
  "is_perfect_square",
366
634
  "is_prime_number",
367
635
  "is_private_ip",
636
+ "is_same_day",
368
637
  "is_string",
369
638
  "is_value_nan",
639
+ "is_weekend",
370
640
  "join_path",
641
+ "js_string",
371
642
  "kebab_case",
372
643
  "key_by",
373
644
  "lazy_filter",
@@ -376,48 +647,85 @@ __all__ = [
376
647
  "lcm",
377
648
  "levenshtein_distance",
378
649
  "linear_congruential_generator",
650
+ "literal_expression",
379
651
  "long_to_ip",
652
+ "map_keys",
653
+ "map_result",
654
+ "map_validator",
655
+ "mask",
656
+ "match_result",
657
+ "matches",
380
658
  "math_converter",
381
659
  "math_separator",
382
660
  "max_value",
383
661
  "median",
662
+ "memoize",
384
663
  "merge_sort",
385
664
  "min_value",
386
665
  "mode",
666
+ "ms_by_unit",
387
667
  "multiples",
388
668
  "multiplication",
389
669
  "n_cr",
390
670
  "n_hr",
391
671
  "n_pr",
672
+ "never_validator",
392
673
  "new_date_int",
393
674
  "new_date_string",
394
675
  "normalize_time_unit",
676
+ "normalize_whitespace",
677
+ "not_",
678
+ "now_simple",
679
+ "number",
680
+ "object_get",
395
681
  "object_has",
396
682
  "object_is_empty",
683
+ "object_is_plain",
684
+ "object_key_by",
397
685
  "object_map_values",
398
686
  "object_merge",
399
687
  "object_merge_deep",
400
688
  "object_omit",
401
689
  "object_pick",
402
690
  "object_pick_deep",
691
+ "object_set",
692
+ "omit_by",
693
+ "once",
694
+ "p_settled",
403
695
  "pad_end",
404
696
  "pad_start",
697
+ "parallel",
405
698
  "parse_email",
406
699
  "parse_json",
700
+ "parse_query_string",
407
701
  "parse_user_agent",
702
+ "pascal_case",
703
+ "path_segments",
408
704
  "percentile",
705
+ "pick_by",
409
706
  "pipe",
410
707
  "pop",
411
708
  "prime_factorization",
412
709
  "quick_sort",
413
710
  "quotient",
414
711
  "rad_to_deg",
712
+ "random_boolean",
713
+ "random_choice",
714
+ "random_float",
415
715
  "random_int",
416
716
  "random_select",
417
717
  "random_string",
418
718
  "random_string_initialization",
719
+ "random_uuid",
720
+ "range_advance",
419
721
  "range_array",
420
722
  "reduce_fraction",
723
+ "remove_prefix",
724
+ "remove_prototype",
725
+ "remove_prototype_deep",
726
+ "remove_prototype_map",
727
+ "remove_prototype_map_deep",
728
+ "remove_suffix",
421
729
  "repeated_trial",
422
730
  "retry",
423
731
  "reverse_string",
@@ -426,34 +734,68 @@ __all__ = [
426
734
  "rgba_to_hsla",
427
735
  "round_of",
428
736
  "safe_execute",
737
+ "sanitize_string",
738
+ "seeded_random",
739
+ "set_of",
429
740
  "shuffle",
430
741
  "shuffle_2d_array",
742
+ "sleep",
431
743
  "slugify",
744
+ "snake_case",
432
745
  "solve_equation",
746
+ "some",
747
+ "split_by_length",
433
748
  "standard_deviation",
749
+ "start_of",
750
+ "string",
434
751
  "string_similarity",
752
+ "strip_ansi",
753
+ "strip_tags",
754
+ "sub_business_days",
755
+ "sub_duration",
435
756
  "subnet_mask_to_cidr",
436
757
  "subtraction",
758
+ "success_function",
759
+ "sum_precise",
760
+ "swap_case",
761
+ "template_literal",
762
+ "throttle",
763
+ "throttle_async",
437
764
  "tim_sort",
765
+ "timeout",
766
+ "title_case",
438
767
  "to_base64",
439
768
  "to_base_n",
440
769
  "to_celsius",
770
+ "to_full_width",
441
771
  "to_half_width",
442
772
  "to_kelvin",
443
773
  "to_ordinal",
774
+ "to_percentage",
775
+ "to_unix",
444
776
  "trim_characters",
445
777
  "trim_end_characters",
446
778
  "trim_start_characters",
447
779
  "truncate",
448
780
  "ultra_number_sort",
781
+ "uncapitalize",
449
782
  "unescape_html",
783
+ "unflatten_object",
450
784
  "uniq_by",
451
785
  "unique",
452
786
  "unit_converter_initialization",
787
+ "unknown_validator",
788
+ "unwrap",
453
789
  "uuidv7",
454
790
  "validate_range",
455
791
  "value_swap",
792
+ "wait_for",
793
+ "week_of_year",
794
+ "weighted_choice",
795
+ "word_count",
796
+ "words",
456
797
  "xoshiro256",
457
798
  "zip_arrays",
458
799
  "zip_longest",
800
+ "zip_to_map",
459
801
  ]
@@ -0,0 +1,317 @@
1
+ Metadata-Version: 2.4
2
+ Name: umt_python
3
+ Version: 0.4.0
4
+ Summary: A Python port of the UMT utility library (array, date, math, string, validate, and related helpers).
5
+ Author-email: riya-amemiya <riyaamemiya@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Bug Tracker, https://github.com/riya-amemiya/UMT/issues
8
+ Project-URL: Homepage, https://github.com/riya-amemiya/UMT
9
+ Project-URL: Repository, https://github.com/riya-amemiya/UMT
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: Utilities
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Dynamic: license-file
23
+
24
+ # UMT Python Package
25
+
26
+ UMT Python Package is a Python port of the TypeScript [`umt`](https://github.com/riya-amemiya/UMT/tree/main/package/main) utility library. `package/main` is the source of truth; this package mirrors those modules (`array`, `date`, `math`, `string`, `validate`, …) with `snake_case` names.
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ pip install umt-python
32
+
33
+ # or using uv
34
+ uv add umt-python
35
+
36
+ # or using poetry
37
+ poetry add umt-python
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ```python
43
+ from umt_python import (
44
+ add_business_days,
45
+ format_string,
46
+ is_between,
47
+ random_string,
48
+ to_base64,
49
+ )
50
+
51
+ random_string(10) # e.g. "aBcD3fGh1j"
52
+ format_string("Hello, {0}! Today is {1}.", "World", "Monday")
53
+ to_base64("Hello World") # "SGVsbG8gV29ybGQ="
54
+
55
+ from datetime import datetime
56
+
57
+ is_between(datetime(2025, 4, 15), datetime(2025, 4, 10), datetime(2025, 4, 20))
58
+ add_business_days(datetime(2025, 4, 18, 9, 30), 1) # 2025-04-21 09:30
59
+ ```
60
+
61
+ Import the published package as `umt_python`. Unit tests in this repo import from `src` (for example `from src.date import is_between`).
62
+
63
+ ## Modules
64
+
65
+ Public names are re-exported from `src/__init__.py`. Grouped the same way as TypeScript:
66
+
67
+ | Module | Examples |
68
+ | --- | --- |
69
+ | `advance` | `range_advance` |
70
+ | `array` | `chunk`, `unique`, `ultra_number_sort`, `zip_arrays` |
71
+ | `async_util` | `sleep`, `parallel`, `timeout`, `debounce_async` |
72
+ | `color` | `hexa_to_rgba`, `rgba_to_hsla` (see below) |
73
+ | `consts` | `ONE_DAY_MS`, `HttpStatus` |
74
+ | `crypto` | `encode_base32`, `decode_base32`, `decode_base58` (see below) |
75
+ | `data_structure` | `LRUCache`, `TTLCache`, `PriorityQueue` |
76
+ | `date` | `is_between`, `add_business_days`, `from_unix` (see below) |
77
+ | `error` | `safe_execute`, `match_result` |
78
+ | `function` | `debounce`, `memoize`, `throttle` |
79
+ | `ip` | `ip_to_long`, `cidr_to_long`, `is_in_range`, `is_private_ip` (see below) |
80
+ | `iterator` | `lazy_map`, `lazy_filter`, `lazy_take` |
81
+ | `map` | `group_by_to_map`, `zip_to_map` |
82
+ | `math` | `gcd`, `n_cr`, `sum_precise`, `calculator`, `math_converter`, `to_base_n` (see below) |
83
+ | `number` | `format_number`, `to_ordinal`, `to_percentage` |
84
+ | `object` | `object_get`, `deep_clone`, `flatten_object` |
85
+ | `predicate` | `every`, `some`, `is_nullish` |
86
+ | `random` | `random_choice`, `seeded_random` |
87
+ | `simple` | `birthday_simple`, `now_simple` |
88
+ | `string` | `format_string`, `slugify`, `strip_ansi`, `strip_tags`, `words`, `normalize_whitespace`, `unescape_html`, `escape_html`, `camel_case`, `kebab_case`, `sanitize_string`, `delete_spaces`, `to_full_width`, `to_half_width` (see below) |
89
+ | `time` | `convert_time` |
90
+ | `tool` | `pipe`, `unwrap`, `parse_json`, `escape_regexp` (see below) |
91
+ | `ua` | `parse_user_agent`, `extract_browser_from_user_agent`, `extract_device_from_user_agent`, `extract_os_from_user_agent` (see below) |
92
+ | `unit` | `to_celsius`, `to_kelvin` |
93
+ | `url` | `build_url`, `parse_query_string`, `is_absolute_url`, `join_path` (see below) |
94
+ | `validate` | `is_number`, `array_of`, `parse_email` (see below) |
95
+
96
+ Not every TypeScript helper is ported yet. There is no `is_same` (use `is_same_day` or compare truncated values with `start_of`). There is no date `format` (TypeScript `format` / Rust `umt_format` / Go `FormatDate`). There is also no `count_by`, `partition`, `sliding`, `map_series`, or `safe_execute_async`.
97
+
98
+ ## Date helpers
99
+
100
+ Local-time calendar helpers aligned with TypeScript `package/main/src/Date`. Week boundaries are Sunday-start (JavaScript `Date#getDay()` 0, not Python `weekday()` Monday=0). There are no UTC variants.
101
+
102
+ | Function | Type | Description | Example |
103
+ | --- | --- | --- | --- |
104
+ | `is_between` | `(date, start, end, unit=None, inclusivity="()") -> bool` | Range check. Default inclusivity is exclusive on both ends. Ranges are **not** swapped. Omit `unit` for exact timestamps; with a unit, all three dates are truncated with `start_of` first. | `is_between(datetime(2025, 4, 15), datetime(2025, 4, 10), datetime(2025, 4, 20)) # True` / `is_between(datetime(2025, 4, 10), datetime(2025, 4, 10), datetime(2025, 4, 20)) # False` / `is_between(datetime(2025, 4, 10), datetime(2025, 4, 10), datetime(2025, 4, 20), None, "[]") # True` |
105
+ | `add_business_days` | `(date, amount, holidays=None) -> datetime` | Walk calendar days until `amount` weekdays (minus optional holidays compared with `is_same_day`) have been counted. Start date is not counted: Friday + 1 is Monday. `0` returns a clone and does not snap to a business day. | `add_business_days(datetime(2025, 4, 18, 9, 30), 1) # datetime(2025, 4, 21, 9, 30)` |
106
+ | `sub_business_days` | `(date, amount, holidays=None) -> datetime` | `add_business_days(date, -amount, holidays)` | `sub_business_days(datetime(2025, 4, 21, 9, 30), 1) # datetime(2025, 4, 18, 9, 30)` |
107
+ | `is_business_day` | `(date, holidays=None) -> bool` | Weekday and not in `holidays` | `is_business_day(datetime(2025, 4, 21)) # True` |
108
+ | `get_quarter` | `(date) -> int` | Local month → 1–4 (Jan–Mar = 1) | `get_quarter(datetime(2025, 4, 15)) # 2` |
109
+ | `week_of_year` | `(date) -> int` | Sunday-start week index. Week 1 contains January 1 of that year. Not ISO-8601. | `week_of_year(datetime(2025, 1, 1)) # 1` / `week_of_year(datetime(2025, 1, 5)) # 2` |
110
+ | `from_unix` | `(value, unit="s") -> datetime` | Epoch to naive local datetime whose timestamp matches JavaScript `Date.getTime()` | `from_unix(0).timestamp() # 0.0` |
111
+ | `to_unix` | `(date, unit="s") -> float` | Default seconds, floored | `to_unix(datetime(1970, 1, 1, tzinfo=timezone.utc)) # 0.0` |
112
+ | `start_of` / `end_of` | `(date, unit) -> datetime` | Boundary truncation. `unit` is `second` \| `minute` \| `hour` \| `day` \| `week` \| `month` \| `quarter` \| `year` | `start_of(datetime(2025, 4, 15, 10, 30), "day") # datetime(2025, 4, 15, 0, 0)` |
113
+
114
+ `DateInclusivity` is `"()"` \| `"[]"` \| `"[)"` \| `"(]"`. `UnixTimeUnit` is `"s"` \| `"ms"`.
115
+
116
+ ## String helpers
117
+
118
+ Unicode-aware helpers aligned with TypeScript `package/main/src/String`.
119
+
120
+ | Function | Type | Description | Example |
121
+ | --- | --- | --- | --- |
122
+ | `strip_ansi` | `(string_: str) -> str` | Removes CSI (colors, cursor, including C1 `U+009B`) and OSC sequences. Incomplete CSI is left unchanged. Unlike `sanitize_string`, other non-printables stay. | `strip_ansi("\x1b[31mred\x1b[0m") # "red"` |
123
+ | `strip_tags` | `(string_: str) -> str` | Deletes HTML/XML tags, repeating until stable so `"<sc<script>ript>"` becomes `""`. Self-closing tags leave no separator. | `strip_tags("<p>Hello <b>World</b></p>") # "Hello World"` |
124
+ | `words` | `(string_: str, pattern: re.Pattern[str] \| None = None) -> list[str]` | Default: camelCase / acronym split, then non-letter/number separators. Pass a compiled pattern to return `findall` matches (`[]` if none). | `words("XMLHttpRequest") # ["XML", "Http", "Request"]` |
125
+ | `normalize_whitespace` | `(string_: str) -> str` | Collapses Unicode `\s+` to a single space and trims. Unlike `delete_spaces`, words stay separated. | `normalize_whitespace("hello world") # "hello world"` |
126
+ | `delete_spaces` | `(string_: str) -> str` | Removes every Unicode `\s` character (spaces, tabs, newlines, em space, ideographic space). | `delete_spaces("Hello World") # "HelloWorld"` / `delete_spaces(" tab\t space ") # "tabspace"` |
127
+ | `sanitize_string` | `(string_: str) -> str` | Keeps printable ASCII (space to tilde) plus TAB / LF / CR. Drops NULL, other C0, DEL, ANSI ESC, and **all non-ASCII** (CJK, emoji, `"é"`). Unlike `strip_ansi`, CSI leftovers remain. | `sanitize_string("\x1b[31mred\x1b[0m") # "[31mred[0m"` / `sanitize_string("héllo") # "hllo"` / `sanitize_string("日本語") # ""` |
128
+ | `unescape_html` | `(string_: str) -> str` | Named entities plus decimal / hex numeric references. `&#X41;` (uppercase `X`) is left unchanged. Decodes via `chr()` — it does **not** apply TypeScript's extra rejection of NULL / C0 / DEL / C1 / surrogates. | `unescape_html("Tom &amp; Jerry") # "Tom & Jerry"` / `unescape_html("&#65;") # "A"` |
129
+ | `escape_html` | `(string_: str) -> str` | Encodes `& < > " '`. Does **not** encode backtick or `/`. TypeScript `escapeHtml` also maps backtick → `&#x60;` and `/` → `&#x2F;`. Cached `re.compile(r"[&<>\"']")`. | `escape_html("<script></script>") # "&lt;script&gt;&lt;/script&gt;"` / `escape_html("Tom & Jerry") # "Tom &amp; Jerry"` |
130
+ | `to_full_width` | `(string_: str) -> str` | ASCII digits and letters only (`0-9A-Za-z`), each code point `+ 0xFEE0`. Punctuation and space stay. `str.maketrans` / `translate`, not regex. | `to_full_width("Abc123") # "Abc123"` / `to_full_width("a-b!") # "a-b!"` |
131
+ | `to_half_width` | `(string_: str) -> str` | **Broader than TypeScript / Rust / Go**: `U+FF01`–`U+FF5E` (full-width `!` through `~`, including digits and letters) plus ideographic space `U+3000` → `" "`. Those ports convert only `0-9A-Za-z`. `str.maketrans` / `translate`, not regex. | `to_half_width("ABC123") # "ABC123"` / `to_half_width("! ") # "! "` |
132
+ | `camel_case` | `(string_: str) -> str` | Replaces non-alphanumeric runs, then lowercases only the first character. Does not split acronyms. | `camel_case("hello-world") # "helloWorld"` / `camel_case("HELLO") # "hELLO"` |
133
+ | `kebab_case` | `(string_: str) -> str` | Inserts dashes on case boundaries and replaces separators. Splits acronyms. | `kebab_case("XMLHttpRequest") # "xml-http-request"` |
134
+ | `slugify` | `(string_: str) -> str` | NFD, strip combining marks, lowercase, hyphenate. Python `\w` is Unicode, so CJK stays: `"Japanese: こんにちは"` → `"japanese-こんにちは"`. TypeScript / Go drop those letters (`"japanese"`). | `slugify("Hello World!") # "hello-world"` / `slugify("Café") # "cafe"` |
135
+
136
+ ## IP helpers
137
+
138
+ IPv4 dotted-decimal only, aligned with TypeScript `package/main/src/IP`. Unlike TypeScript, these functions validate input and raise `ValueError` (or `TypeError` from `get_network_address`) on malformed values.
139
+
140
+ | Function | Type | Description | Example |
141
+ | --- | --- | --- | --- |
142
+ | `ip_to_long` / `long_to_ip` | `(ip: str) -> int` / `(long: int \| float) -> str` | Pack or unpack four octets. Rejects leading zeros (`"192.168.01.1"`). | `ip_to_long("192.168.1.1") # 3232235777` / `long_to_ip(3232235777) # "192.168.1.1"` |
143
+ | `cidr_to_long` / `cidr_to_subnet_mask` | `(cidr: int) -> int` / `(cidr: int) -> str` | Prefix `0`–`32`. Outside that range raises `ValueError`. | `cidr_to_long(24) # 4294967040` / `cidr_to_subnet_mask(24) # "255.255.255.0"` |
144
+ | `subnet_mask_to_cidr` | `(subnet_mask: str) -> int` | Requires contiguous `1` bits then `0` bits. `"255.0.255.0"` raises. TypeScript `subnetMaskToCidr` only counts bits. | `subnet_mask_to_cidr("255.255.255.0") # 24` |
145
+ | `is_in_range` | `(remote_ip, network_ip, cidr) -> bool` | `(ip & mask) == (network & mask)`. CIDR `0` matches every IPv4 address. | `is_in_range("192.168.1.2", "192.168.1.0", 24) # True` |
146
+ | `is_private_ip` | `(ip: str) -> bool` | RFC 1918 only: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`. Loopback and link-local are not private. The three `(network, mask)` pairs are computed once at module load (TypeScript / Rust / Go do the same). Invalid input raises `ValueError`. | `is_private_ip("10.0.0.1") # True` / `is_private_ip("127.0.0.1") # False` |
147
+ | `get_ip_class` | `(ip: str) -> str` | Classful first-octet lookup (`A`–`E`). `0.0.0.0` and malformed input return `""`. | `get_ip_class("10.0.0.1") # "A"` |
148
+ | `get_network_address` | `(ip: str, subnet_mask: str) -> int` | Returns an unsigned 32-bit **int**, not a dotted string. | `get_network_address("192.168.1.1", "255.255.255.0") # 3232235776` |
149
+ | `ip_to_binary_string` | `(ip: str) -> str` | 32-character `0`/`1` string, eight bits per octet. | `ip_to_binary_string("192.168.0.1") # "11000000101010000000000000000001"` |
150
+
151
+ ## Color and URL helpers
152
+
153
+ | Function | Type | Description | Example |
154
+ | --- | --- | --- | --- |
155
+ | `hexa_to_rgba` | `(hex_code: str) -> dict[str, float]` | `#` plus 3, 6, or 8 hex digits → `{r, g, b, a}`. `a` is `0`–`1` rounded to 2 decimals. Invalid input raises `ValueError`. TypeScript `hexaToRgba` does not validate. | `hexa_to_rgba("#FF0000") # {'r': 255, 'g': 0, 'b': 0, 'a': 1.0}` / `hexa_to_rgba("#fff") # {'r': 255, 'g': 255, 'b': 255, 'a': 1.0}` |
156
+ | `is_absolute_url` | `(url: str) -> bool` | RFC 3986 scheme check (letter, then letters / digits / `+` / `.` / `-`, then `:`). Protocol-relative URLs are not absolute. | `is_absolute_url("https://example.com") # True` / `is_absolute_url("//example.com") # False` |
157
+ | `join_path` | `(*segments: str) -> str` | Slash-normalizing string join, not `os.path.join`. Keeps the first segment's leading `/` and the last segment's trailing `/`. Empty pieces are dropped. No `.` / `..` resolution. No segments → `""`. A single `"///"` stays `"///"`. | `join_path("https://example.com/", "/api/", "/users") # "https://example.com/api/users"` / `join_path("a", "", "b") # "a/b"` |
158
+
159
+ `escape_regexp(string)` (in `tool`) prefixes `$ ( ) * + . ? [ \ ] ^ { | }` with a backslash. Hyphen and `/` are not escaped. `calculator` builds its currency-symbol regex with this helper at call time.
160
+
161
+ ```python
162
+ from umt_python import escape_regexp, join_path
163
+
164
+ escape_regexp("a.b") # "a\\.b"
165
+ escape_regexp("foo-bar") # "foo-bar"
166
+ escape_regexp("path/to/file.txt") # "path/to/file\\.txt"
167
+ join_path("https://example.com/", "/api/", "/users") # "https://example.com/api/users"
168
+ ```
169
+
170
+ ## Crypto helpers
171
+
172
+ RFC 4648 Base32 (`A-Z` + `2-7`, `=` padding), aligned with TypeScript `package/main/src/Crypto`. Encoding, not encryption.
173
+
174
+ | Function | Type | Description | Example |
175
+ | --- | --- | --- | --- |
176
+ | `encode_base32` | `(input_data: str \| bytes) -> str` | UTF-8 encode a string first. Empty input → `""`. Pads to a multiple of 8 with `=`. | `encode_base32("Hello") # "JBSWY3DP"` / `encode_base32("f") # "MY======"` |
177
+ | `decode_base32` | `(input_data: str) -> bytes` | Skips `=` anywhere. **Raises `ValueError`** on invalid / lowercase characters (`"1A"`, `"jbswy3dp"`). TypeScript `decodeBase32` maps those to value `0` and does not throw. | `decode_base32("JBSWY3DP") # b"Hello"` / `decode_base32("JB=SWY3DP") # b"Hello"` |
178
+ | `decode_base32_to_string` | `(input_data: str) -> str` | UTF-8 decode of `decode_base32`. | `decode_base32_to_string("JBSWY3DP") # "Hello"` |
179
+
180
+ ## parse_email
181
+
182
+ `parse_email(email, ParseEmailOptions(level=...))` returns `ParseEmailResult(valid, parts)`. `level` is required: `"basic"` \| `"rfc822"` \| `"rfc2822"` \| `"rfc5321"` \| `"rfc5322"`. There is **no** TypeScript 320-character pre-check.
183
+
184
+ ```python
185
+ from umt_python import ParseEmailOptions, parse_email
186
+
187
+ parse_email("user@example.com", ParseEmailOptions(level="basic")).valid # True
188
+ parse_email("user@localhost", ParseEmailOptions(level="basic")).valid # True
189
+ parse_email("user@localhost", ParseEmailOptions(level="rfc5321")).valid # False
190
+ ```
191
+
192
+ `rfc822` allows single-label domains and comments. `rfc2822` requires a TLD and rejects `..`. `rfc5321` is the SMTP path (max 256 / local 64, domain literals allowed). `rfc5322` adds comments and quoted strings.
193
+
194
+ ## Math helpers
195
+
196
+ | Function | Type | Description | Example |
197
+ | --- | --- | --- | --- |
198
+ | `calculator` | `(expression: str, exchange=None) -> str` | Strips whitespace. `=` solves a single-variable equation (`"x=5"` → `"5"`). Otherwise evaluates `+ - * / ^` and parentheses. Incomplete input is returned as-is. `^` reduces the last pair first (`"2^2^2"` → `"16"`). | `calculator("1+2") # "3"` / `calculator("$10*2", {"$": 100}) # "2000"` |
199
+ | `math_converter` | `(equation: str) -> str` | Rewrites `n*n` or `n^2` as a sum of simpler products. Uses `float` in the rewritten terms, so the string is `"1500.0*1000+…"` rather than TypeScript / Go `"1500*1000+…"`. | `math_converter("1250*1250") # "1500.0*1000+400.0*100+200.0*100+50*50"` |
200
+ | `to_base_n` | `(value: int, radix: int = 2) -> str` | Default radix is **2** (`to_base_n(10)` → `"1010"`). Hex digits are lowercase. Radix 2 / 8 / 10 / 16 use format strings (`f"{value:d}"` for 10). `bool` is accepted as `int` (`True` → `"1"`). Rust returns `"Invalid radix"` and Go panics on a base outside `2`–`36`; this function does not check that range. | `to_base_n(15, 16) # "f"` / `to_base_n(255, 16) # "ff"` / `to_base_n(-10, 10) # "-10"` |
201
+
202
+ ## UA helpers
203
+
204
+ Coarse User-Agent labels aligned with TypeScript `package/main/src/UA`. Matching is case-insensitive. `parse_user_agent` lowercases the input, then calls the three extractors. Not a full UA parser (no versions).
205
+
206
+ | Function | Type | Description | Example |
207
+ | --- | --- | --- | --- |
208
+ | `extract_browser_from_user_agent` | `(ua: str) -> BrowserType` | Order: Edge → IE → Firefox → Opera (`opr/`, returned as **`"other"`**) → Chrome (`chrome` / `crios`) → Safari → `"other"`. | `extract_browser_from_user_agent("… Chrome/91 … OPR/77") # "other"` |
209
+ | `extract_device_from_user_agent` | `(ua: str) -> DeviceType` | Bots first, then iPhone / iPod / webOS / BlackBerry / Opera Mini as `"mobile"`. Android with `mobile` → `"mobile"`; Android without `mobile` → `"tablet"`. iPad is `"tablet"`. | `extract_device_from_user_agent("Mozilla/5.0 (iPad; CPU OS 14_6 like Mac OS X)") # "tablet"` |
210
+ | `extract_os_from_user_agent` | `(ua: str) -> OsType` | iPhone / iPad / iPod → `"ios"` even when the string contains `like Mac OS X`. Android wins over the `Linux` token. | `extract_os_from_user_agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)") # "macos"` |
211
+ | `parse_user_agent` | `(user_agent: str) -> UserAgentInfo` | TypedDict `{browser, device, os}`. | `parse_user_agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/91.0") # {'browser': 'chrome', 'device': 'desktop', 'os': 'macos'}` |
212
+
213
+ Fixed regexes in this package are compiled once at module level (`re.compile`): UA extractors, `hexa_to_rgba`, `is_absolute_url`, `join_path`, `math_converter`, `parse_email`, `strip_ansi` / `strip_tags`, `unescape_html`, `escape_html`, `camel_case`, `kebab_case`, `slugify`, `normalize_whitespace`, `sanitize_string`, `delete_spaces`, `escape_regexp`, calculator / `calculator_core` (except the currency-symbol pattern), `literal_expression`, `apply_formatter`, `get_value`. Caller-built patterns (`format_string`, `regex_match`, optional `words` pattern, `template_literal`, calculator currency symbol) stay inline. `to_full_width` / `to_half_width` use module-level `str.maketrans` tables, not regex.
214
+
215
+ ## Function List
216
+
217
+ ### String Manipulation Functions
218
+
219
+ | Function | Type | Description | Example |
220
+ |----------|------|-------------|---------|
221
+ | `delete_spaces` | `(string_: str) -> str` | Remove all whitespace characters from a string | `delete_spaces("Hello World") # "HelloWorld"` |
222
+ | `format_string` | `(template: str, *values: object) -> str` | Replace placeholders {0}, {1}, etc. in a template string | `format_string("Sum of {0} and {1} is {2}", 1, 2, 3) # "Sum of 1 and 2 is 3"` |
223
+ | `reverse_string` | `(char: str) -> str` | Reverse a string | `reverse_string("Hello") # "olleH"` |
224
+ | `escape_html` | `(string_: str) -> str` | Encode `& < > " '` (not backtick or `/`) | `escape_html("<b>") # "&lt;b&gt;"` |
225
+ | `to_full_width` | `(string_: str) -> str` | Convert ASCII digits and letters to full-width | `to_full_width("Abc123") # "Abc123"` |
226
+ | `to_half_width` | `(string_: str) -> str` | Convert `U+FF01`–`U+FF5E` and ideographic space to half-width | `to_half_width("Hello 123") # "Hello 123"` |
227
+
228
+ ### Base64 Encoding Functions
229
+
230
+ | Function | Type | Description | Example |
231
+ |----------|------|-------------|---------|
232
+ | `to_base64` | `(char: str) -> str` | Encode a string to Base64 | `to_base64("Hello") # "SGVsbG8="` |
233
+ | `from_base64` | `(base64_string: str) -> str` | Decode a Base64 string | `from_base64("SGVsbG8=") # "Hello"` |
234
+
235
+ ### String Padding Functions
236
+
237
+ | Function | Type | Description | Example |
238
+ |----------|------|-------------|---------|
239
+ | `pad_start` | `(string_: str, target_length: int, pad_string: str) -> str` | Pad string from the start to reach target length | `pad_start("123", 5, "0") # "00123"` |
240
+ | `pad_end` | `(string_: str, target_length: int, pad_string: str) -> str` | Pad string from the end to reach target length | `pad_end("abc", 5, "0") # "abc00"` |
241
+
242
+ ### String Trimming Functions
243
+
244
+ | Function | Type | Description | Example |
245
+ |----------|------|-------------|---------|
246
+ | `trim_characters` | `(string_: str, chars: str) -> str` | Remove specified characters from both ends | `trim_characters("-.-hello-.-", "-.") # "hello"` |
247
+ | `trim_start_characters` | `(string_: str, chars: str) -> str` | Remove specified characters from the start | `trim_start_characters("!!!hello", "!") # "hello"` |
248
+ | `trim_end_characters` | `(string_: str, chars: str) -> str` | Remove specified characters from the end | `trim_end_characters("hello!!!", "!") # "hello"` |
249
+
250
+ ### Random String Generation
251
+
252
+ | Function | Type | Description | Example |
253
+ |----------|------|-------------|---------|
254
+ | `random_string` | `(size: int = 8, char_pool: str = DEFAULT_RANDOM_STRING_CHARS) -> str` | Generate a random string of specified length | `random_string(10) # "aBcD3fGh1j"` |
255
+ | `random_string_initialization` | `(char_pool: str = DEFAULT_RANDOM_STRING_CHARS) -> Callable[[int], str]` | Create a custom random string generator with specific character pool | `custom_random = random_string_initialization("xyz")` → `custom_random(3) # "xyx"` |
256
+
257
+ ### String Validation Functions
258
+
259
+ | Function | Type | Description | Example |
260
+ |----------|------|-------------|---------|
261
+ | `has_no_letters` | `(text: str) -> bool` | Check if string contains no letters (only numbers, emojis, special chars) | `has_no_letters("123!@#") # True` / `has_no_letters("abc123") # False` |
262
+
263
+ ### Number Functions
264
+
265
+ | Function | Type | Description | Example |
266
+ |----------|------|-------------|---------|
267
+ | `format_number` | `(value: float \| int, *, locale: str \| None = None, minimum_fraction_digits: int \| None = None, maximum_fraction_digits: int \| None = None, style: Literal["decimal", "currency", "percent"] = "decimal", currency: str \| None = None) -> str` | Format a number with locale-aware separators, fraction-digit controls, and decimal/percent/currency styles. Mirrors `Intl.NumberFormat` from the TypeScript source. | `format_number(1234567.89) # "1,234,567.89"` / `format_number(1234567.89, locale="de-DE") # "1.234.567,89"` / `format_number(0.75, style="percent") # "75%"` / `format_number(1234.5, style="currency", currency="USD") # "$1,234.50"` |
268
+ | `to_ordinal` | `(value: int \| float) -> str` | Convert a number to its English ordinal string (handles 11th/12th/13th specially) | `to_ordinal(1) # "1st"` / `to_ordinal(11) # "11th"` / `to_ordinal(21) # "21st"` |
269
+ | `to_percentage` | `(value: float \| int, total: float \| int, decimals: int = 2) -> float` | Calculate the percentage of a value relative to a total (returns 0 when total is 0) | `to_percentage(1, 3) # 33.33` / `to_percentage(25, 100) # 25.0` |
270
+
271
+ ## Constants
272
+
273
+ - `DEFAULT_RANDOM_STRING_CHARS`: Default character pool for random string generation (ASCII letters + digits)
274
+
275
+ ## Constraints
276
+
277
+ - **Python 3.10+** (`requires-python = ">=3.10"`). CI currently runs 3.10–3.15.
278
+ - `bool` is a subclass of `int` in Python. Numeric validators must reject `True` / `False` explicitly so they do not treat them as `1` / `0`.
279
+ - Exact arithmetic in math helpers uses `decimal.Decimal` constructed from strings, to match JavaScript number-string behavior.
280
+ - Date week math uses Sunday-start weeks. Do not assume ISO weeks (`datetime.isocalendar()`).
281
+ - IP helpers are IPv4 only. They validate input (TypeScript does not). `subnet_mask_to_cidr` requires a contiguous mask; TypeScript `subnetMaskToCidr` only counts set bits. `is_private_ip` is RFC 1918 only (not loopback or link-local). The three RFC 1918 `(network, mask)` pairs are hoisted at module load, matching TypeScript / Rust / Go.
282
+ - `decode_base32` raises `ValueError` on invalid / lowercase characters. TypeScript `decodeBase32` maps those to `0`.
283
+ - `to_base_n` defaults to radix 2. `True` / `False` are `1` / `0` because `bool` is an `int`.
284
+ - `hexa_to_rgba` requires `#` plus 3, 6, or 8 hex digits. TypeScript `hexaToRgba` does not validate.
285
+ - `unescape_html` decodes numeric entities with `chr()`. TypeScript `unescapeHtml` additionally rejects NULL, most C0 controls, DEL, C1, surrogates, and out-of-range values.
286
+ - `escape_html` encodes `& < > " '` only. TypeScript `escapeHtml` also encodes backtick (`&#x60;`) and `/` (`&#x2F;`).
287
+ - `to_full_width` converts ASCII alnum only. `to_half_width` also converts full-width punctuation (`U+FF01`–`U+FF5E`) and ideographic space; TypeScript / Rust / Go `toHalfWidth` convert digits and letters only.
288
+ - `slugify` keeps Unicode letters (Python `\w`). TypeScript / Go `slugify` use ASCII `\w` and drop CJK.
289
+ - `parse_email` requires `ParseEmailOptions`. It does not apply TypeScript's 320-character ReDoS cap.
290
+ - `math_converter` formats split terms with `float` (`"1500.0*1000+…"`). TypeScript / Rust / Go emit integers (`"1500*1000+…"`).
291
+ - UA helpers are coarse labels. Opera (`OPR/`) is `"other"`. Android without a `mobile` token is `"tablet"`. iPhone UAs that contain `like Mac OS X` are `"ios"`.
292
+ - `sanitize_string` is ASCII-only. CJK, emoji, and accented letters are dropped. It is not `strip_ansi`: `"\x1b[31mred\x1b[0m"` becomes `"[31mred[0m"`.
293
+ - `join_path` does not resolve `.` / `..` and does not use OS separators.
294
+ - `escape_regexp` does not escape `-` or `/`.
295
+
296
+ ## Development
297
+
298
+ This project uses `uv`. Prefer the Makefile targets (same commands as CI):
299
+
300
+ ```bash
301
+ make install # uv sync
302
+ make test # uv run pytest
303
+ make lint # ruff format --check && ruff check
304
+ make format # uv run ruff format
305
+ make typecheck # uv run pyright
306
+ make all # format, lint, typecheck, test
307
+ ```
308
+
309
+ Tests live under `tests/unit/` (mirroring `src/`) and import from `src`:
310
+
311
+ ```python
312
+ from src.date import is_between
313
+ ```
314
+
315
+ ## License
316
+
317
+ MIT License
@@ -0,0 +1,6 @@
1
+ umt_python/__init__.py,sha256=4QFgc7NQqb7KDI-61jEhYhuBTJtqSNySeCuJQH6f0pU,15160
2
+ umt_python-0.4.0.dist-info/licenses/LICENSE,sha256=1sfH4YyDPcU1Flbmf9AwxZHlsxt0bMsoU7TpSvVPaTo,1069
3
+ umt_python-0.4.0.dist-info/METADATA,sha256=DdPwDTxVcRy06SpVCpl3FJTYRYPGWMIeJzUhTol1pXA,26974
4
+ umt_python-0.4.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
5
+ umt_python-0.4.0.dist-info/top_level.txt,sha256=JMzQArGg6QV0n-BiGlvfXempE7t93p2i0-2bH3XUkEk,11
6
+ umt_python-0.4.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (82.0.0)
2
+ Generator: setuptools (84.2.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,132 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: umt_python
3
- Version: 0.2.0
4
- Summary: A collection of useful utility functions for various tasks in Python, focusing on string manipulation and formatting.
5
- Author-email: riya-amemiya <riyaamemiya@gmail.com>
6
- License-Expression: MIT
7
- Project-URL: Bug Tracker, https://github.com/riya-amemiya/UMT/issues
8
- Project-URL: Homepage, https://github.com/riya-amemiya/UMT
9
- Project-URL: Repository, https://github.com/riya-amemiya/UMT
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: Programming Language :: Python :: 3.13
15
- Classifier: Programming Language :: Python :: 3.14
16
- Classifier: Operating System :: OS Independent
17
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
- Classifier: Topic :: Utilities
19
- Requires-Python: >=3.10
20
- Description-Content-Type: text/markdown
21
- License-File: LICENSE
22
- Dynamic: license-file
23
-
24
- # UMT Python Package
25
-
26
- UMT Python Package is a collection of useful utility functions for various tasks in Python, focusing on string manipulation and formatting.
27
-
28
- ## Install
29
-
30
- ```bash
31
- pip install umt-python
32
-
33
- # or using uv
34
- uv add umt-python
35
-
36
- # or using poetry
37
- poetry add umt-python
38
- ```
39
-
40
- ## Quick Start
41
-
42
- ```python
43
- from umt_python import random_string, format_string, to_base64
44
-
45
- # Generate a random string
46
- random_str = random_string(10)
47
- print(random_str) # e.g., "aBcD3fGh1j"
48
-
49
- # Format a string with placeholders
50
- formatted = format_string("Hello, {0}! Today is {1}.", "World", "Monday")
51
- print(formatted) # "Hello, World! Today is Monday."
52
-
53
- # Encode string to Base64
54
- encoded = to_base64("Hello World")
55
- print(encoded) # "SGVsbG8gV29ybGQ="
56
- ```
57
-
58
- ## Function List
59
-
60
- ### String Manipulation Functions
61
-
62
- | Function | Type | Description | Example |
63
- |----------|------|-------------|---------|
64
- | `delete_spaces` | `(string_: str) -> str` | Remove all whitespace characters from a string | `delete_spaces("Hello World") # "HelloWorld"` |
65
- | `format_string` | `(template: str, *values: object) -> str` | Replace placeholders {0}, {1}, etc. in a template string | `format_string("Sum of {0} and {1} is {2}", 1, 2, 3) # "Sum of 1 and 2 is 3"` |
66
- | `reverse_string` | `(char: str) -> str` | Reverse a string | `reverse_string("Hello") # "olleH"` |
67
- | `to_half_width` | `(string_: str) -> str` | Convert full-width characters to half-width | `to_half_width("Hello 123") # "Hello 123"` |
68
-
69
- ### Base64 Encoding Functions
70
-
71
- | Function | Type | Description | Example |
72
- |----------|------|-------------|---------|
73
- | `to_base64` | `(char: str) -> str` | Encode a string to Base64 | `to_base64("Hello") # "SGVsbG8="` |
74
- | `from_base64` | `(base64_string: str) -> str` | Decode a Base64 string | `from_base64("SGVsbG8=") # "Hello"` |
75
-
76
- ### String Padding Functions
77
-
78
- | Function | Type | Description | Example |
79
- |----------|------|-------------|---------|
80
- | `pad_start` | `(string_: str, target_length: int, pad_string: str) -> str` | Pad string from the start to reach target length | `pad_start("123", 5, "0") # "00123"` |
81
- | `pad_end` | `(string_: str, target_length: int, pad_string: str) -> str` | Pad string from the end to reach target length | `pad_end("abc", 5, "0") # "abc00"` |
82
-
83
- ### String Trimming Functions
84
-
85
- | Function | Type | Description | Example |
86
- |----------|------|-------------|---------|
87
- | `trim_characters` | `(string_: str, chars: str) -> str` | Remove specified characters from both ends | `trim_characters("-.-hello-.-", "-.") # "hello"` |
88
- | `trim_start_characters` | `(string_: str, chars: str) -> str` | Remove specified characters from the start | `trim_start_characters("!!!hello", "!") # "hello"` |
89
- | `trim_end_characters` | `(string_: str, chars: str) -> str` | Remove specified characters from the end | `trim_end_characters("hello!!!", "!") # "hello"` |
90
-
91
- ### Random String Generation
92
-
93
- | Function | Type | Description | Example |
94
- |----------|------|-------------|---------|
95
- | `random_string` | `(size: int = 8, char_pool: str = DEFAULT_RANDOM_STRING_CHARS) -> str` | Generate a random string of specified length | `random_string(10) # "aBcD3fGh1j"` |
96
- | `random_string_initialization` | `(char_pool: str = DEFAULT_RANDOM_STRING_CHARS) -> Callable[[int], str]` | Create a custom random string generator with specific character pool | `custom_random = random_string_initialization("xyz")` → `custom_random(3) # "xyx"` |
97
-
98
- ### String Validation Functions
99
-
100
- | Function | Type | Description | Example |
101
- |----------|------|-------------|---------|
102
- | `has_no_letters` | `(text: str) -> bool` | Check if string contains no letters (only numbers, emojis, special chars) | `has_no_letters("123!@#") # True` / `has_no_letters("abc123") # False` |
103
-
104
- ## Constants
105
-
106
- - `DEFAULT_RANDOM_STRING_CHARS`: Default character pool for random string generation (ASCII letters + digits)
107
-
108
- ## Requirements
109
-
110
- - Python 3.9 or higher
111
-
112
- ## Development
113
-
114
- This project uses `uv` for dependency management.
115
-
116
- ```bash
117
- # Install dependencies
118
- uv sync
119
-
120
- # Run tests
121
- uv run pytest
122
-
123
- # Format code
124
- uv run ruff format
125
-
126
- # Lint code
127
- uv run ruff check
128
- ```
129
-
130
- ## License
131
-
132
- MIT License
@@ -1,6 +0,0 @@
1
- umt_python/__init__.py,sha256=Q46wkUI6c2atLpR1qqIGhQqbtvXWDbV75ywUaVwgSIw,8737
2
- umt_python-0.2.0.dist-info/licenses/LICENSE,sha256=1sfH4YyDPcU1Flbmf9AwxZHlsxt0bMsoU7TpSvVPaTo,1069
3
- umt_python-0.2.0.dist-info/METADATA,sha256=koT12tuAdfDtqCsJbmAaGeIUH-_3_kP_XkFgC2zl22Q,5164
4
- umt_python-0.2.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
5
- umt_python-0.2.0.dist-info/top_level.txt,sha256=JMzQArGg6QV0n-BiGlvfXempE7t93p2i0-2bH3XUkEk,11
6
- umt_python-0.2.0.dist-info/RECORD,,