@@ -74,7 +74,7 @@ class FeatureView(BaseFeatureView):
7474
7575 name : str
7676 entities : List [str ]
77- ttl : timedelta
77+ ttl : Optional [ timedelta ]
7878 batch_source : DataSource
7979 stream_source : Optional [DataSource ]
8080 features : List [Feature ]
@@ -87,9 +87,10 @@ class FeatureView(BaseFeatureView):
8787 @log_exceptions
8888 def __init__ (
8989 self ,
90- name : str ,
91- entities : List [str ],
92- ttl : Union [Duration , timedelta ],
90+ * args ,
91+ name : Optional [str ] = None ,
92+ entities : Optional [List [str ]] = None ,
93+ ttl : Optional [Union [Duration , timedelta ]] = None ,
9394 batch_source : Optional [DataSource ] = None ,
9495 stream_source : Optional [DataSource ] = None ,
9596 features : Optional [List [Feature ]] = None ,
@@ -121,6 +122,54 @@ def __init__(
121122 Raises:
122123 ValueError: A field mapping conflicts with an Entity or a Feature.
123124 """
125+
126+ positional_attributes = ["name, entities, ttl" ]
127+
128+ _name = name
129+ _entities = entities
130+ _ttl = ttl
131+
132+ if args :
133+ warnings .warn (
134+ (
135+ "feature view parameters should be specified as a keyword argument instead of a positional arg."
136+ "Feast 0.23+ will not support positional arguments to construct feature views"
137+ ),
138+ DeprecationWarning ,
139+ )
140+ if len (args ) > len (positional_attributes ):
141+ raise ValueError (
142+ f"Only { ', ' .join (positional_attributes )} are allowed as positional args when defining "
143+ f"feature views, for backwards compatibility."
144+ )
145+ if len (args ) >= 1 :
146+ _name = args [0 ]
147+ if len (args ) >= 2 :
148+ _entities = args [1 ]
149+ if len (args ) >= 3 :
150+ _ttl = args [2 ]
151+
152+ if not _name :
153+ raise ValueError ("feature view name needs to be specified" )
154+
155+ self .name = _name
156+ self .entities = _entities if _entities else [DUMMY_ENTITY_NAME ]
157+
158+ if isinstance (_ttl , Duration ):
159+ self .ttl = timedelta (seconds = int (_ttl .seconds ))
160+ warnings .warn (
161+ (
162+ "The option to pass a Duration object to the ttl parameter is being deprecated. "
163+ "Please pass a timedelta object instead. Feast 0.21 and onwards will not support "
164+ "Duration objects."
165+ ),
166+ DeprecationWarning ,
167+ )
168+ elif isinstance (_ttl , timedelta ) or _ttl is None :
169+ self .ttl = _ttl
170+ else :
171+ raise ValueError (f"unknown value type specified for ttl { type (_ttl )} " )
172+
124173 _features = features or []
125174
126175 if stream_source is not None and isinstance (stream_source , PushSource ):
@@ -138,7 +187,7 @@ def __init__(
138187 )
139188 self .batch_source = batch_source
140189
141- cols = [entity for entity in entities ] + [feat .name for feat in _features ]
190+ cols = [entity for entity in self . entities ] + [feat .name for feat in _features ]
142191 for col in cols :
143192 if (
144193 self .batch_source .field_mapping is not None
@@ -150,22 +199,13 @@ def __init__(
150199 f"Entity or Feature name."
151200 )
152201
153- super ().__init__ (name , _features , description , tags , owner )
154- self .entities = entities if entities else [DUMMY_ENTITY_NAME ]
155-
156- if isinstance (ttl , Duration ):
157- self .ttl = timedelta (seconds = int (ttl .seconds ))
158- warnings .warn (
159- (
160- "The option to pass a Duration object to the ttl parameter is being deprecated. "
161- "Please pass a timedelta object instead. Feast 0.21 and onwards will not support "
162- "Duration objects."
163- ),
164- DeprecationWarning ,
165- )
166- else :
167- self .ttl = ttl
168-
202+ super ().__init__ (
203+ name = name ,
204+ features = _features ,
205+ description = description ,
206+ tags = tags ,
207+ owner = owner ,
208+ )
169209 self .online = online
170210 self .stream_source = stream_source
171211 self .materialization_intervals = []
0 commit comments