oakscriptpy 0.1.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.
oakscriptpy/str_.py ADDED
@@ -0,0 +1,166 @@
1
+ """String namespace — mirrors PineScript str.* functions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re as _re
6
+ from datetime import datetime, timezone
7
+
8
+
9
+ def length(s: str) -> int:
10
+ return len(s)
11
+
12
+
13
+ def tostring(value: object, fmt: str | None = None) -> str:
14
+ if isinstance(value, (int, float)) and fmt:
15
+ decimals = len(fmt.split(".")[1]) if "." in fmt else 0
16
+ return f"{value:.{decimals}f}"
17
+ return str(value)
18
+
19
+
20
+ def tonumber(s: str) -> float | None:
21
+ try:
22
+ return float(s)
23
+ except (ValueError, TypeError):
24
+ return None
25
+
26
+
27
+ def substring(s: str, begin: int, end: int | None = None) -> str:
28
+ if end is None:
29
+ return s[begin:]
30
+ return s[begin:end]
31
+
32
+
33
+ def upper(s: str) -> str:
34
+ return s.upper()
35
+
36
+
37
+ def lower(s: str) -> str:
38
+ return s.lower()
39
+
40
+
41
+ def contains(source: str, sub: str) -> bool:
42
+ return sub in source
43
+
44
+
45
+ def pos(source: str, sub: str) -> int:
46
+ return source.find(sub)
47
+
48
+
49
+ def replace(source: str, target: str, replacement: str, occurrence: int | None = None) -> str:
50
+ if occurrence == 0:
51
+ return source.replace(target, replacement, 1)
52
+ return source.replace(target, replacement)
53
+
54
+
55
+ def replace_all(source: str, target: str, replacement: str) -> str:
56
+ return source.replace(target, replacement)
57
+
58
+
59
+ def split(s: str, separator: str) -> list[str]:
60
+ return s.split(separator)
61
+
62
+
63
+ def concat(*strings: str) -> str:
64
+ return "".join(strings)
65
+
66
+
67
+ def format(format_str: str, *args: object) -> str:
68
+ result = format_str
69
+ for i, arg in enumerate(args):
70
+ result = result.replace(f"{{{i}}}", str(arg))
71
+ return result
72
+
73
+
74
+ def startswith(source: str, prefix: str) -> bool:
75
+ return source.startswith(prefix)
76
+
77
+
78
+ def endswith(source: str, suffix: str) -> bool:
79
+ return source.endswith(suffix)
80
+
81
+
82
+ def char_at(s: str, position: int) -> str:
83
+ if 0 <= position < len(s):
84
+ return s[position]
85
+ return ""
86
+
87
+
88
+ def trim(s: str) -> str:
89
+ return s.strip()
90
+
91
+
92
+ def trim_left(s: str) -> str:
93
+ return s.lstrip()
94
+
95
+
96
+ def trim_right(s: str) -> str:
97
+ return s.rstrip()
98
+
99
+
100
+ def match(source: str, regex: str) -> bool:
101
+ return bool(_re.search(regex, source))
102
+
103
+
104
+ def repeat(source: str, count: int, separator: str = "") -> str | None:
105
+ if source is None:
106
+ return None
107
+ if count <= 0:
108
+ return ""
109
+ return separator.join([source] * count)
110
+
111
+
112
+ def format_time(time_ms: int, fmt: str) -> str:
113
+ dt = datetime.fromtimestamp(time_ms / 1000, tz=timezone.utc)
114
+
115
+ month_names = [
116
+ "January", "February", "March", "April", "May", "June",
117
+ "July", "August", "September", "October", "November", "December",
118
+ ]
119
+ month_names_short = [
120
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
121
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
122
+ ]
123
+
124
+ year = dt.year
125
+ month = dt.month - 1
126
+ day = dt.day
127
+ hours = dt.hour
128
+ minutes = dt.minute
129
+ seconds = dt.second
130
+
131
+ hours12 = hours % 12 or 12
132
+ ampm = "AM" if hours < 12 else "PM"
133
+
134
+ replacements = [
135
+ ("yyyy", str(year)),
136
+ ("yy", str(year)[-2:]),
137
+ ("MMMM", month_names[month]),
138
+ ("MMM", month_names_short[month]),
139
+ ("MM", f"{month + 1:02d}"),
140
+ ("M", str(month + 1)),
141
+ ("dd", f"{day:02d}"),
142
+ ("d", str(day)),
143
+ ("HH", f"{hours:02d}"),
144
+ ("H", str(hours)),
145
+ ("hh", f"{hours12:02d}"),
146
+ ("h", str(hours12)),
147
+ ("mm", f"{minutes:02d}"),
148
+ ("m", str(minutes)),
149
+ ("ss", f"{seconds:02d}"),
150
+ ("s", str(seconds)),
151
+ ("a", ampm),
152
+ ]
153
+
154
+ # Two-pass replacement using unique tokens
155
+ tokens: list[str] = []
156
+ result = fmt
157
+ for i, (pattern, value) in enumerate(replacements):
158
+ token = f"\ufff0{i}\ufff1"
159
+ result = result.replace(pattern, token)
160
+ tokens.append(value)
161
+
162
+ for i, value in enumerate(tokens):
163
+ token = f"\ufff0{i}\ufff1"
164
+ result = result.replace(token, value)
165
+
166
+ return result