build(deps): update tweepy 3.10.0 -> 4.14.0
diff --git a/erpnext/crm/doctype/twitter_settings/twitter_settings.py b/erpnext/crm/doctype/twitter_settings/twitter_settings.py
index 42874dd..442aa77 100644
--- a/erpnext/crm/doctype/twitter_settings/twitter_settings.py
+++ b/erpnext/crm/doctype/twitter_settings/twitter_settings.py
@@ -10,7 +10,6 @@
 from frappe.model.document import Document
 from frappe.utils import get_url_to_form
 from frappe.utils.file_manager import get_file_path
-from tweepy.error import TweepError
 
 
 class TwitterSettings(Document):
@@ -21,20 +20,22 @@
 				frappe.utils.get_url()
 			)
 		)
-		auth = tweepy.OAuthHandler(
+		auth = tweepy.OAuth1UserHandler(
 			self.consumer_key, self.get_password(fieldname="consumer_secret"), callback_url
 		)
 		try:
 			redirect_url = auth.get_authorization_url()
 			return redirect_url
-		except tweepy.TweepError as e:
+		except (tweepy.TweepyException, tweepy.HTTPException) as e:
 			frappe.msgprint(_("Error! Failed to get request token."))
 			frappe.throw(
 				_("Invalid {0} or {1}").format(frappe.bold("Consumer Key"), frappe.bold("Consumer Secret Key"))
 			)
 
 	def get_access_token(self, oauth_token, oauth_verifier):
-		auth = tweepy.OAuthHandler(self.consumer_key, self.get_password(fieldname="consumer_secret"))
+		auth = tweepy.OAuth1UserHandler(
+			self.consumer_key, self.get_password(fieldname="consumer_secret")
+		)
 		auth.request_token = {"oauth_token": oauth_token, "oauth_token_secret": oauth_verifier}
 
 		try:
@@ -59,13 +60,15 @@
 
 			frappe.local.response["type"] = "redirect"
 			frappe.local.response["location"] = get_url_to_form("Twitter Settings", "Twitter Settings")
-		except TweepError as e:
+		except (tweepy.TweepyException, tweepy.HTTPException) as e:
 			frappe.msgprint(_("Error! Failed to get access token."))
 			frappe.throw(_("Invalid Consumer Key or Consumer Secret Key"))
 
 	def get_api(self):
 		# authentication of consumer key and secret
-		auth = tweepy.OAuthHandler(self.consumer_key, self.get_password(fieldname="consumer_secret"))
+		auth = tweepy.OAuth1UserHandler(
+			self.consumer_key, self.get_password(fieldname="consumer_secret")
+		)
 		# authentication of access token and secret
 		auth.set_access_token(self.access_token, self.access_token_secret)
 
@@ -96,21 +99,21 @@
 
 			return response
 
-		except TweepError as e:
+		except (tweepy.TweepyException, tweepy.HTTPException) as e:
 			self.api_error(e)
 
 	def delete_tweet(self, tweet_id):
 		api = self.get_api()
 		try:
 			api.destroy_status(tweet_id)
-		except TweepError as e:
+		except (tweepy.TweepyException, tweepy.HTTPException) as e:
 			self.api_error(e)
 
 	def get_tweet(self, tweet_id):
 		api = self.get_api()
 		try:
 			response = api.get_status(tweet_id, trim_user=True, include_entities=True)
-		except TweepError as e:
+		except (tweepy.TweepyException, tweepy.HTTPException) as e:
 			self.api_error(e)
 
 		return response._json
diff --git a/pyproject.toml b/pyproject.toml
index 3e0dfb2..7841c92 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -20,7 +20,7 @@
     "googlemaps",
     "plaid-python~=7.2.1",
     "python-youtube~=0.8.0",
-    "tweepy~=3.10.0",
+    "tweepy~=4.14.0",
 
     # Not used directly - required by PyQRCode for PNG generation
     "pypng~=0.20220715.0",