33import os
44import sys
55from datetime import datetime , timedelta
6- from typing import Any , Dict , Optional , Union
6+ from typing import Any , Callable , Dict , Optional , Union
77from typing_extensions import Unpack
88from uuid import uuid4
99
@@ -99,6 +99,34 @@ def add_context_tags(properties):
9999 return properties
100100
101101
102+ def no_throw (default_return = None ):
103+ """
104+ Decorator to prevent raising exceptions from public API methods.
105+ Note that this doesn't prevent errors from propagating via `on_error`.
106+ Exceptions will still be raised if the debug flag is enabled.
107+
108+ Args:
109+ default_return: Value to return on exception (default: None)
110+ """
111+
112+ def decorator (func ):
113+ from functools import wraps
114+
115+ @wraps (func )
116+ def wrapper (self , * args , ** kwargs ):
117+ try :
118+ return func (self , * args , ** kwargs )
119+ except Exception as e :
120+ if self .debug :
121+ raise e
122+ self .log .exception (f"Error in { func .__name__ } : { e } " )
123+ return default_return
124+
125+ return wrapper
126+
127+ return decorator
128+
129+
102130class Client (object ):
103131 """
104132 This is the SDK reference for the PostHog Python SDK.
@@ -303,9 +331,9 @@ def feature_flags(self, flags):
303331 for flag in self ._feature_flags
304332 if flag .get ("key" ) is not None
305333 }
306- assert self . feature_flags_by_key is not None , (
307- " feature_flags_by_key should be initialized when feature_flags is set"
308- )
334+ assert (
335+ self . feature_flags_by_key is not None
336+ ), "feature_flags_by_key should be initialized when feature_flags is set"
309337
310338 def get_feature_variants (
311339 self ,
@@ -481,6 +509,7 @@ def get_flags_decision(
481509
482510 return normalize_flags_response (resp_data )
483511
512+ @no_throw ()
484513 def capture (
485514 self , event : str , ** kwargs : Unpack [OptionalCaptureArgs ]
486515 ) -> Optional [str ]:
@@ -657,6 +686,7 @@ def _parse_send_feature_flags(self, send_feature_flags) -> SendFeatureFlagsOptio
657686 f"Expected bool or dict."
658687 )
659688
689+ @no_throw ()
660690 def set (self , ** kwargs : Unpack [OptionalSetArgs ]) -> Optional [str ]:
661691 """
662692 Set properties on a person profile.
@@ -690,6 +720,8 @@ def set(self, **kwargs: Unpack[OptionalSetArgs]) -> Optional[str]:
690720
691721 Category:
692722 Identification
723+
724+ Note: This method will not raise exceptions. Errors are logged.
693725 """
694726 distinct_id = kwargs .get ("distinct_id" , None )
695727 properties = kwargs .get ("properties" , None )
@@ -716,6 +748,7 @@ def set(self, **kwargs: Unpack[OptionalSetArgs]) -> Optional[str]:
716748
717749 return self ._enqueue (msg , disable_geoip )
718750
751+ @no_throw ()
719752 def set_once (self , ** kwargs : Unpack [OptionalSetArgs ]) -> Optional [str ]:
720753 """
721754 Set properties on a person profile only if they haven't been set before.
@@ -734,6 +767,8 @@ def set_once(self, **kwargs: Unpack[OptionalSetArgs]) -> Optional[str]:
734767
735768 Category:
736769 Identification
770+
771+ Note: This method will not raise exceptions. Errors are logged.
737772 """
738773 distinct_id = kwargs .get ("distinct_id" , None )
739774 properties = kwargs .get ("properties" , None )
@@ -759,6 +794,7 @@ def set_once(self, **kwargs: Unpack[OptionalSetArgs]) -> Optional[str]:
759794
760795 return self ._enqueue (msg , disable_geoip )
761796
797+ @no_throw ()
762798 def group_identify (
763799 self ,
764800 group_type : str ,
@@ -791,6 +827,8 @@ def group_identify(
791827
792828 Category:
793829 Identification
830+
831+ Note: This method will not raise exceptions. Errors are logged.
794832 """
795833 properties = properties or {}
796834
@@ -815,6 +853,7 @@ def group_identify(
815853
816854 return self ._enqueue (msg , disable_geoip )
817855
856+ @no_throw ()
818857 def alias (
819858 self ,
820859 previous_id : str ,
@@ -840,6 +879,8 @@ def alias(
840879
841880 Category:
842881 Identification
882+
883+ Note: This method will not raise exceptions. Errors are logged.
843884 """
844885 (distinct_id , personless ) = get_identity_state (distinct_id )
845886
@@ -1526,9 +1567,9 @@ def _locally_evaluate_flag(
15261567 response = None
15271568
15281569 if self .feature_flags :
1529- assert self . feature_flags_by_key is not None , (
1530- " feature_flags_by_key should be initialized when feature_flags is set"
1531- )
1570+ assert (
1571+ self . feature_flags_by_key is not None
1572+ ), "feature_flags_by_key should be initialized when feature_flags is set"
15321573 # Local evaluation
15331574 flag = self .feature_flags_by_key .get (key )
15341575 if flag :
0 commit comments