@@ -1317,14 +1317,14 @@ def __init__(
13171317 self .app = app
13181318 self ._datastore = datastore
13191319 self ._register_blueprint = register_blueprint
1320- self .mail_util_cls = mail_util_cls
1321- self .password_util_cls = password_util_cls
1322- self .phone_util_cls = phone_util_cls
1320+ self ._mail_util_cls = mail_util_cls
1321+ self ._password_util_cls = password_util_cls
1322+ self ._phone_util_cls = phone_util_cls
13231323 self .render_template = render_template
1324- self .totp_cls = totp_cls
1325- self .username_util_cls = username_util_cls
1326- self .webauthn_util_cls = webauthn_util_cls
1327- self .mf_recovery_codes_util_cls = mf_recovery_codes_util_cls
1324+ self ._totp_cls = totp_cls
1325+ self ._username_util_cls = username_util_cls
1326+ self ._webauthn_util_cls = webauthn_util_cls
1327+ self ._mf_recovery_codes_util_cls = mf_recovery_codes_util_cls
13281328 self ._oauth = oauth
13291329
13301330 # Forms - we create a list from constructor.
@@ -1543,7 +1543,7 @@ def init_app(
15431543 ):
15441544 self ._use_confirm_form = False
15451545
1546- # The following will be set as attributes and initialized from either
1546+ # The following will be set as attributes and initialized from constructor or
15471547 # kwargs or config.
15481548 attr_names = [
15491549 "trackable" ,
@@ -1558,17 +1558,32 @@ def init_app(
15581558 "username_recovery" ,
15591559 "passwordless" ,
15601560 "webauthn" ,
1561+ "render_template" ,
1562+ "datetime_factory" ,
1563+ ]
1564+ for attr in attr_names :
1565+ if ov := kwargs .get (attr , cv (attr .upper (), app , strict = False )):
1566+ setattr (self , attr , ov )
1567+
1568+ # Deprecated BC attrs - only settable at constructor time. Noter that newer
1569+ # _util classes (username_util_cls) already are this way
1570+ dep_attr_names = [
15611571 "mail_util_cls" ,
15621572 "password_util_cls" ,
15631573 "phone_util_cls" ,
1564- "render_template" ,
15651574 "totp_cls" ,
15661575 "webauthn_util_cls" ,
1567- "datetime_factory" ,
15681576 ]
1569- for attr in attr_names :
1577+ for attr in dep_attr_names :
15701578 if ov := kwargs .get (attr , cv (attr .upper (), app , strict = False )):
1571- setattr (self , attr , ov )
1579+ setattr (self , f"_{ attr } " , ov )
1580+ warnings .warn (
1581+ f"Setting { attr } via kwargs or config is"
1582+ " deprecated as of version 5.6.1 and will be removed in a future"
1583+ " release. Use the Flask-Security constructor." ,
1584+ DeprecationWarning ,
1585+ stacklevel = 2 ,
1586+ )
15721587
15731588 identity_loaded .connect_via (app )(_on_identity_loaded )
15741589
@@ -1597,12 +1612,12 @@ def init_app(
15971612 )
15981613
15991614 self .login_manager = _get_login_manager (app , self )
1600- self ._phone_util = self .phone_util_cls (app )
1601- self ._mail_util = self .mail_util_cls (app )
1602- self ._password_util = self .password_util_cls (app )
1603- self ._username_util = self .username_util_cls (app )
1604- self ._webauthn_util = self .webauthn_util_cls (app )
1605- self ._mf_recovery_codes_util = self .mf_recovery_codes_util_cls (app )
1615+ self ._phone_util = self ._phone_util_cls (app )
1616+ self ._mail_util = self ._mail_util_cls (app )
1617+ self ._password_util = self ._password_util_cls (app )
1618+ self ._username_util = self ._username_util_cls (app )
1619+ self ._webauthn_util = self ._webauthn_util_cls (app )
1620+ self ._mf_recovery_codes_util = self ._mf_recovery_codes_util_cls (app )
16061621 self .remember_token_serializer = _get_serializer (app , "remember" )
16071622 self .login_serializer = _get_serializer (app , "login" )
16081623 self .reset_serializer = _get_serializer (app , "reset" )
@@ -1768,22 +1783,22 @@ def init_app(
17681783 sms_service = cv ("SMS_SERVICE" , app = app )
17691784 if sms_service == "Twilio" : # pragma: no cover
17701785 self ._check_modules ("twilio" , "SMS" )
1771- if self .phone_util_cls == PhoneUtil :
1786+ if self ._phone_util_cls == PhoneUtil :
17721787 self ._check_modules ("phonenumbers" , "SMS" )
17731788
17741789 secrets = cv ("TOTP_SECRETS" , app = app )
17751790 issuer = cv ("TOTP_ISSUER" , app = app )
17761791 if not secrets or not issuer :
17771792 raise ValueError ("Both TOTP_SECRETS and TOTP_ISSUER must be set" )
1778- self ._totp_factory = self .totp_cls (secrets , issuer )
1793+ self ._totp_factory = self ._totp_cls (secrets , issuer )
17791794
17801795 if cv ("PASSWORD_COMPLEXITY_CHECKER" , app = app ) == "zxcvbn" :
17811796 self ._check_modules ("zxcvbn" , "PASSWORD_COMPLEXITY_CHECKER" )
17821797
17831798 if cv ("WEBAUTHN" , app = app ):
17841799 self ._check_modules ("webauthn" , "WEBAUTHN" )
17851800
1786- if cv ("USERNAME_ENABLE" , app = app ) and self .username_util_cls == UsernameUtil :
1801+ if cv ("USERNAME_ENABLE" , app = app ) and self ._username_util_cls == UsernameUtil :
17871802 self ._check_modules ("bleach" , "USERNAME_ENABLE" )
17881803
17891804 # Register so other packages can reference our translations.
@@ -2048,6 +2063,48 @@ def reauthn_handler(
20482063 """
20492064 self ._reauthn_handler = cb
20502065
2066+ @property
2067+ def mail_util (self ) -> MailUtil :
2068+ """Instance of mail_util_cls created at init_app() time.
2069+ See :ref:`api:extendable classes`"""
2070+ return self ._mail_util
2071+
2072+ @property
2073+ def password_util (self ) -> PasswordUtil :
2074+ """Instance of password_util_cls created at init_app() time.
2075+ See :ref:`api:extendable classes`"""
2076+ return self ._password_util
2077+
2078+ @property
2079+ def username_util (self ) -> UsernameUtil :
2080+ """Instance of username_util_cls created at init_app() time.
2081+ See :ref:`api:extendable classes`"""
2082+ return self ._username_util
2083+
2084+ @property
2085+ def phone_util (self ) -> PhoneUtil :
2086+ """Instance of phone_util_cls created at init_app() time.
2087+ See :ref:`api:extendable classes`"""
2088+ return self ._phone_util
2089+
2090+ @property
2091+ def totp_factory (self ) -> Totp :
2092+ """Instance of totp_factory created at init_app() time.
2093+ See :ref:`api:extendable classes`"""
2094+ return self ._totp_factory
2095+
2096+ @property
2097+ def mf_recovery_codes_util (self ) -> MfRecoveryCodesUtil :
2098+ """Instance of mf_recovery_codes_util_cls created at init_app() time.
2099+ See :ref:`api:extendable classes`"""
2100+ return self ._mf_recovery_codes_util
2101+
2102+ @property
2103+ def webauthn_util (self ) -> WebauthnUtil :
2104+ """Instance of webauthn_util_cls created at init_app() time.
2105+ See :ref:`api:extendable classes`"""
2106+ return self ._webauthn_util
2107+
20512108 def _add_ctx_processor (
20522109 self , endpoint : str , fn : t .Callable [[], dict [str , t .Any ]]
20532110 ) -> None :
0 commit comments