11from __future__ import annotations
22
3- from narwhals ._plan .common import Function
3+ from typing import TYPE_CHECKING
4+
5+ from narwhals ._plan .common import ExprNamespace , Function , IRNamespace
46from narwhals ._plan .options import FunctionFlags , FunctionOptions
57
8+ if TYPE_CHECKING :
9+ from narwhals ._plan .dummy import DummyExpr
10+
611
712class StringFunction (Function ):
813 @property
@@ -30,15 +35,20 @@ def __repr__(self) -> str:
3035
3136
3237class Contains (StringFunction ):
33- __slots__ = ("literal" ,)
38+ __slots__ = ("literal" , "pattern" )
3439
40+ pattern : str
3541 literal : bool
3642
3743 def __repr__ (self ) -> str :
3844 return "str.contains"
3945
4046
4147class EndsWith (StringFunction ):
48+ __slots__ = ("suffix" ,)
49+
50+ suffix : str
51+
4252 def __repr__ (self ) -> str :
4353 return "str.ends_with"
4454
@@ -49,9 +59,12 @@ def __repr__(self) -> str:
4959
5060
5161class Replace (StringFunction ):
52- __slots__ = ("literal" ,)
62+ __slots__ = ("literal" , "n" , "pattern" , "value" )
5363
64+ pattern : str
65+ value : str
5466 literal : bool
67+ n : int
5568
5669 def __repr__ (self ) -> str :
5770 return "str.replace"
@@ -63,8 +76,10 @@ class ReplaceAll(StringFunction):
6376 https://github.com/pola-rs/polars/blob/dafd0a2d0e32b52bcfa4273bffdd6071a0d5977a/crates/polars-plan/src/dsl/function_expr/strings.rs#L65-L70
6477 """
6578
66- __slots__ = ("literal" ,)
79+ __slots__ = ("literal" , "pattern" , "value" )
6780
81+ pattern : str
82+ value : str
6883 literal : bool
6984
7085 def __repr__ (self ) -> str :
@@ -88,35 +103,29 @@ def __repr__(self) -> str:
88103 return "str.slice"
89104
90105
91- class Head (StringFunction ):
92- __slots__ = ("n" ,)
93-
94- n : int
95-
96- def __repr__ (self ) -> str :
97- return "str.head"
98-
99-
100- class Tail (StringFunction ):
101- __slots__ = ("n" ,)
102-
103- n : int
104-
105- def __repr__ (self ) -> str :
106- return "str.tail"
106+ class Split (StringFunction ):
107+ __slots__ = ("by" ,)
107108
109+ by : str
108110
109- class Split (StringFunction ):
110111 def __repr__ (self ) -> str :
111112 return "str.split"
112113
113114
114115class StartsWith (StringFunction ):
116+ __slots__ = ("prefix" ,)
117+
118+ prefix : str
119+
115120 def __repr__ (self ) -> str :
116121 return "str.startswith"
117122
118123
119124class StripChars (StringFunction ):
125+ __slots__ = ("characters" ,)
126+
127+ characters : str | None
128+
120129 def __repr__ (self ) -> str :
121130 return "str.strip_chars"
122131
@@ -133,6 +142,9 @@ class ToDatetime(StringFunction):
133142
134143 format : str | None
135144
145+ def __repr__ (self ) -> str :
146+ return "str.to_datetime"
147+
136148
137149class ToLowercase (StringFunction ):
138150 def __repr__ (self ) -> str :
@@ -142,3 +154,123 @@ def __repr__(self) -> str:
142154class ToUppercase (StringFunction ):
143155 def __repr__ (self ) -> str :
144156 return "str.to_uppercase"
157+
158+
159+ class IRStringNamespace (IRNamespace ):
160+ def len_chars (self ) -> LenChars :
161+ return LenChars ()
162+
163+ def replace (
164+ self , pattern : str , value : str , * , literal : bool = False , n : int = 1
165+ ) -> Replace :
166+ return Replace (pattern = pattern , value = value , literal = literal , n = n )
167+
168+ def replace_all (
169+ self , pattern : str , value : str , * , literal : bool = False
170+ ) -> ReplaceAll :
171+ return ReplaceAll (pattern = pattern , value = value , literal = literal )
172+
173+ def strip_chars (self , characters : str | None = None ) -> StripChars :
174+ return StripChars (characters = characters )
175+
176+ def starts_with (self , prefix : str ) -> StartsWith :
177+ return StartsWith (prefix = prefix )
178+
179+ def ends_with (self , suffix : str ) -> EndsWith :
180+ return EndsWith (suffix = suffix )
181+
182+ def contains (self , pattern : str , * , literal : bool = False ) -> Contains :
183+ return Contains (pattern = pattern , literal = literal )
184+
185+ def slice (self , offset : int , length : int | None = None ) -> Slice :
186+ return Slice (offset = offset , length = length )
187+
188+ def head (self , n : int = 5 ) -> Slice :
189+ return self .slice (0 , n )
190+
191+ def tail (self , n : int = 5 ) -> Slice :
192+ return self .slice (- n )
193+
194+ def split (self , by : str ) -> Split :
195+ return Split (by = by )
196+
197+ def to_datetime (self , format : str | None = None ) -> ToDatetime :
198+ return ToDatetime (format = format )
199+
200+ def to_lowercase (self ) -> ToUppercase :
201+ return ToUppercase ()
202+
203+ def to_uppercase (self ) -> ToLowercase :
204+ return ToLowercase ()
205+
206+
207+ class ExprStringNamespace (ExprNamespace [IRStringNamespace ]):
208+ @property
209+ def _ir_namespace (self ) -> type [IRStringNamespace ]:
210+ return IRStringNamespace
211+
212+ def len_chars (self ) -> DummyExpr :
213+ return self ._to_narwhals (self ._ir .len_chars ().to_function_expr (self ._expr ._ir ))
214+
215+ def replace (
216+ self , pattern : str , value : str , * , literal : bool = False , n : int = 1
217+ ) -> DummyExpr :
218+ return self ._to_narwhals (
219+ self ._ir .replace (pattern , value , literal = literal , n = n ).to_function_expr (
220+ self ._expr ._ir
221+ )
222+ )
223+
224+ def replace_all (
225+ self , pattern : str , value : str , * , literal : bool = False
226+ ) -> DummyExpr :
227+ return self ._to_narwhals (
228+ self ._ir .replace_all (pattern , value , literal = literal ).to_function_expr (
229+ self ._expr ._ir
230+ )
231+ )
232+
233+ def strip_chars (self , characters : str | None = None ) -> DummyExpr :
234+ return self ._to_narwhals (
235+ self ._ir .strip_chars (characters ).to_function_expr (self ._expr ._ir )
236+ )
237+
238+ def starts_with (self , prefix : str ) -> DummyExpr :
239+ return self ._to_narwhals (
240+ self ._ir .starts_with (prefix ).to_function_expr (self ._expr ._ir )
241+ )
242+
243+ def ends_with (self , suffix : str ) -> DummyExpr :
244+ return self ._to_narwhals (
245+ self ._ir .ends_with (suffix ).to_function_expr (self ._expr ._ir )
246+ )
247+
248+ def contains (self , pattern : str , * , literal : bool = False ) -> DummyExpr :
249+ return self ._to_narwhals (
250+ self ._ir .contains (pattern , literal = literal ).to_function_expr (self ._expr ._ir )
251+ )
252+
253+ def slice (self , offset : int , length : int | None = None ) -> DummyExpr :
254+ return self ._to_narwhals (
255+ self ._ir .slice (offset , length ).to_function_expr (self ._expr ._ir )
256+ )
257+
258+ def head (self , n : int = 5 ) -> DummyExpr :
259+ return self ._to_narwhals (self ._ir .head (n ).to_function_expr (self ._expr ._ir ))
260+
261+ def tail (self , n : int = 5 ) -> DummyExpr :
262+ return self ._to_narwhals (self ._ir .tail (n ).to_function_expr (self ._expr ._ir ))
263+
264+ def split (self , by : str ) -> DummyExpr :
265+ return self ._to_narwhals (self ._ir .split (by ).to_function_expr (self ._expr ._ir ))
266+
267+ def to_datetime (self , format : str | None = None ) -> DummyExpr :
268+ return self ._to_narwhals (
269+ self ._ir .to_datetime (format ).to_function_expr (self ._expr ._ir )
270+ )
271+
272+ def to_lowercase (self ) -> DummyExpr :
273+ return self ._to_narwhals (self ._ir .to_lowercase ().to_function_expr (self ._expr ._ir ))
274+
275+ def to_uppercase (self ) -> DummyExpr :
276+ return self ._to_narwhals (self ._ir .to_uppercase ().to_function_expr (self ._expr ._ir ))
0 commit comments