requirements: Upgrade Python requirements.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2024-01-28 15:32:21 -08:00 committed by Tim Abbott
parent e56863fa85
commit 93198a19ed
68 changed files with 2602 additions and 2496 deletions

View File

@ -60,9 +60,7 @@ def generate_time_series_data(
f"Must be generating at least 2 data points. Currently generating {length}"
)
growth_base = growth ** (1.0 / (length - 1))
values_no_noise = [
seasonality[i % len(seasonality)] * (growth_base**i) for i in range(length)
]
values_no_noise = [seasonality[i % len(seasonality)] * (growth_base**i) for i in range(length)]
noise_scalars = [rng.gauss(0, 1)]
for i in range(1, length):

View File

@ -266,18 +266,18 @@ def support(
context["error_message"] = error.message
else:
do_change_realm_subdomain(realm, new_subdomain, acting_user=acting_user)
request.session[
"success_message"
] = f"Subdomain changed from {old_subdomain} to {new_subdomain}"
request.session["success_message"] = (
f"Subdomain changed from {old_subdomain} to {new_subdomain}"
)
return HttpResponseRedirect(
reverse("support") + "?" + urlencode({"q": new_subdomain})
)
elif status is not None:
if status == "active":
do_send_realm_reactivation_email(realm, acting_user=acting_user)
context[
"success_message"
] = f"Realm reactivation email sent to admins of {realm.string_id}."
context["success_message"] = (
f"Realm reactivation email sent to admins of {realm.string_id}."
)
elif status == "deactivated":
do_deactivate_realm(realm, acting_user=acting_user)
context["success_message"] = f"{realm.string_id} deactivated."
@ -569,9 +569,9 @@ def remote_servers_support(
remote_server
)
except MissingDataError:
remote_server_to_max_monthly_messages[
remote_server.id
] = "Recent analytics data missing"
remote_server_to_max_monthly_messages[remote_server.id] = (
"Recent analytics data missing"
)
context["remote_servers"] = remote_servers
context["remote_servers_support_data"] = server_support_data

View File

@ -449,10 +449,10 @@ def catch_stripe_errors(func: Callable[ParamT, ReturnT]) -> Callable[ParamT, Ret
# See https://stripe.com/docs/api/python#error_handling, though
# https://stripe.com/docs/api/ruby#error_handling suggests there are additional fields, and
# https://stripe.com/docs/error-codes gives a more detailed set of error codes
except stripe.error.StripeError as e:
except stripe.StripeError as e:
assert isinstance(e.json_body, dict)
err = e.json_body.get("error", {})
if isinstance(e, stripe.error.CardError):
if isinstance(e, stripe.CardError):
billing_logger.info(
"Stripe card error: %s %s %s %s",
e.http_status,
@ -469,9 +469,7 @@ def catch_stripe_errors(func: Callable[ParamT, ReturnT]) -> Callable[ParamT, Ret
err.get("code"),
err.get("param"),
)
if isinstance(
e, (stripe.error.RateLimitError, stripe.error.APIConnectionError)
): # nocoverage TODO
if isinstance(e, (stripe.RateLimitError, stripe.APIConnectionError)): # nocoverage TODO
raise StripeConnectionError(
"stripe connection error",
_("Something went wrong. Please wait a few seconds and try again."),
@ -979,7 +977,7 @@ class BillingSession(ABC):
off_session=True,
payment_method=stripe_customer.invoice_settings.default_payment_method,
)
except stripe.error.CardError as e:
except stripe.CardError as e:
raise StripeCardError("card error", e.user_message)
PaymentIntent.objects.create(
@ -1398,9 +1396,9 @@ class BillingSession(ABC):
# to worry about this plan being used for any other purpose.
# NOTE: This is the 2nd plan for the customer.
plan_params["status"] = CustomerPlan.NEVER_STARTED
plan_params[
"invoicing_status"
] = CustomerPlan.INVOICING_STATUS_INITIAL_INVOICE_TO_BE_SENT
plan_params["invoicing_status"] = (
CustomerPlan.INVOICING_STATUS_INITIAL_INVOICE_TO_BE_SENT
)
event_time = timezone_now().replace(microsecond=0)
# Schedule switching to the new plan at plan end date.

View File

@ -153,9 +153,9 @@ class Session(models.Model):
session_dict["status"] = self.get_status_as_string()
session_dict["type"] = self.get_type_as_string()
session_dict[
"is_manual_license_management_upgrade_session"
] = self.is_manual_license_management_upgrade_session
session_dict["is_manual_license_management_upgrade_session"] = (
self.is_manual_license_management_upgrade_session
)
session_dict["tier"] = self.tier
event = self.get_last_associated_event()
if event is not None:

View File

@ -163,7 +163,7 @@ def generate_and_save_stripe_fixture(
request_mock.add_passthru("https://api.stripe.com")
# Talk to Stripe
stripe_object = mocked_function(*args, **kwargs)
except stripe.error.StripeError as e:
except stripe.StripeError as e:
with open(fixture_path, "w") as f:
assert e.headers is not None
error_dict = {**vars(e), "headers": dict(e.headers)}
@ -193,12 +193,12 @@ def read_stripe_fixture(
fixture = orjson.loads(f.read())
# Check for StripeError fixtures
if "json_body" in fixture:
requester = stripe.api_requestor.APIRequestor()
requester = stripe._api_requestor._APIRequestor()
# This function will raise the relevant StripeError according to the fixture
requester.interpret_response(
requester._interpret_response(
fixture["http_body"], fixture["http_status"], fixture["headers"]
)
return stripe.util.convert_to_stripe_object(fixture)
return stripe.convert_to_stripe_object(fixture)
return _read_stripe_fixture
@ -257,9 +257,9 @@ def normalize_fixture_data(
# why we're doing something a bit more complicated
for i, timestamp_field in enumerate(tested_timestamp_fields):
# Don't use (..) notation, since the matched timestamp can easily appear in other fields
pattern_translations[
f'"{timestamp_field}": 1[5-9][0-9]{{8}}(?![0-9-])'
] = f'"{timestamp_field}": 1{i+1:02}%07d'
pattern_translations[f'"{timestamp_field}": 1[5-9][0-9]{{8}}(?![0-9-])'] = (
f'"{timestamp_field}": 1{i+1:02}%07d'
)
normalized_values: Dict[str, Dict[str, str]] = {pattern: {} for pattern in pattern_translations}
for fixture_file in fixture_files_for_function(decorated_function):
@ -752,7 +752,7 @@ class StripeTest(StripeTestCase):
def test_catch_stripe_errors(self) -> None:
@catch_stripe_errors
def raise_invalid_request_error() -> None:
raise stripe.error.InvalidRequestError("message", "param", "code", json_body={})
raise stripe.InvalidRequestError("message", "param", "code", json_body={})
with self.assertLogs("corporate.stripe", "ERROR") as error_log:
with self.assertRaises(BillingError) as billing_context:
@ -766,9 +766,7 @@ class StripeTest(StripeTestCase):
def raise_card_error() -> None:
error_message = "The card number is not a valid credit card number."
json_body = {"error": {"message": error_message}}
raise stripe.error.CardError(
error_message, "number", "invalid_number", json_body=json_body
)
raise stripe.CardError(error_message, "number", "invalid_number", json_body=json_body)
with self.assertLogs("corporate.stripe", "INFO") as info_log:
with self.assertRaises(StripeCardError) as card_context:
@ -2166,7 +2164,7 @@ class StripeTest(StripeTestCase):
"tier": None,
},
)
with self.assertRaises(stripe.error.CardError):
with self.assertRaises(stripe.CardError):
# We don't have to handle this since the Stripe Checkout page would
# ask Customer to enter a valid card number. trigger_stripe_checkout_session_completed_webhook
# emulates what happens in the Stripe Checkout page. Adding this check mostly for coverage of

View File

@ -554,9 +554,8 @@ def remote_billing_legacy_server_login(
# authenticated as a billing admin for this remote server, so we need to store
# our usual IdentityDict structure in the session.
request.session["remote_billing_identities"] = {}
request.session["remote_billing_identities"][
f"remote_server:{remote_server_uuid}"
] = LegacyServerIdentityDict(
request.session["remote_billing_identities"][f"remote_server:{remote_server_uuid}"] = (
LegacyServerIdentityDict(
remote_server_uuid=remote_server_uuid,
authenticated_at=datetime_to_timestamp(timezone_now()),
# The lack of remote_billing_user_id indicates the auth hasn't been completed.
@ -564,6 +563,7 @@ def remote_billing_legacy_server_login(
# to the next step in the flow is permitted with this.
remote_billing_user_id=None,
)
)
context = {
"remote_server_hostname": remote_server.hostname,
@ -755,15 +755,15 @@ def remote_billing_legacy_server_from_login_confirmation_link(
# if the user came here e.g. in a different browser than they
# started the login flow in.)
request.session["remote_billing_identities"] = {}
request.session["remote_billing_identities"][
f"remote_server:{remote_server_uuid}"
] = LegacyServerIdentityDict(
request.session["remote_billing_identities"][f"remote_server:{remote_server_uuid}"] = (
LegacyServerIdentityDict(
remote_server_uuid=remote_server_uuid,
authenticated_at=datetime_to_timestamp(timezone_now()),
# Having a remote_billing_user_id indicates the auth has been completed.
# The user will now be granted access to authenticated endpoints.
remote_billing_user_id=remote_billing_user.id,
)
)
next_page = prereg_object.next_page
assert next_page in VALID_NEXT_PAGES

View File

@ -6,7 +6,6 @@ from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.http import HttpRequest, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from stripe.webhook import Webhook
from corporate.lib.stripe import STRIPE_API_VERSION
from corporate.lib.stripe_event_handler import (
@ -27,14 +26,14 @@ def stripe_webhook(request: HttpRequest) -> HttpResponse:
): # nocoverage: We can't verify the signature in test suite since we fetch the events
# from Stripe events API and manually post to the webhook endpoint.
try:
stripe_event = Webhook.construct_event(
stripe_event = stripe.Webhook.construct_event(
request.body,
request.headers["Stripe-Signature"],
stripe_webhook_endpoint_secret,
)
except ValueError:
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError:
except stripe.SignatureVerificationError:
return HttpResponse(status=400)
else:
assert not settings.PRODUCTION

View File

@ -137,7 +137,7 @@ lxml
django-two-factor-auth[call,phonenumberslite,sms]
# Needed for processing payments (in corporate)
stripe<7.8.0 # https://github.com/stripe/stripe-python/issues/1158
stripe
# For checking whether email of the user is from a disposable email provider.
disposable-email-domains

View File

@ -62,7 +62,7 @@ cairosvg
python-debian
# Pattern-based lint tool
semgrep
semgrep<1.53.0 # https://github.com/boto/botocore/issues/2926
# Contains Pysa, a security-focused static analyzer
pyre-check

File diff suppressed because it is too large Load Diff

View File

@ -11,9 +11,9 @@ alabaster==0.7.13 \
--hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
--hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
# via sphinx
babel==2.13.1 \
--hash=sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900 \
--hash=sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed
babel==2.14.0 \
--hash=sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363 \
--hash=sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287
# via sphinx
certifi==2023.11.17 \
--hash=sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1 \
@ -126,13 +126,13 @@ imagesize==1.4.1 \
--hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
--hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
# via sphinx
importlib-metadata==7.0.0 \
--hash=sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7 \
--hash=sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67
importlib-metadata==7.0.1 \
--hash=sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e \
--hash=sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc
# via sphinx
jinja2==3.1.2 \
--hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
--hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
jinja2==3.1.3 \
--hash=sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa \
--hash=sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90
# via
# myst-parser
# sphinx
@ -142,67 +142,67 @@ markdown-it-py==3.0.0 \
# via
# mdit-py-plugins
# myst-parser
markupsafe==2.1.3 \
--hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
--hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
--hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
--hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
--hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
--hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
--hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
--hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
--hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
--hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
--hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
--hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
--hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
--hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
--hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
--hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
--hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
--hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
--hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
--hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
--hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
--hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
--hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
--hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
--hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
--hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
--hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
--hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
--hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
--hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
--hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
--hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
--hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
--hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
--hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
--hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
--hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
--hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
--hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
--hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
--hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
--hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
--hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
--hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
--hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
--hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
--hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
--hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
--hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
--hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
--hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
--hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
--hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
--hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
--hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
--hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
--hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
--hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
--hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
--hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
markupsafe==2.1.4 \
--hash=sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69 \
--hash=sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0 \
--hash=sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d \
--hash=sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec \
--hash=sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5 \
--hash=sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411 \
--hash=sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3 \
--hash=sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74 \
--hash=sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0 \
--hash=sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949 \
--hash=sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d \
--hash=sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279 \
--hash=sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f \
--hash=sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6 \
--hash=sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc \
--hash=sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e \
--hash=sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954 \
--hash=sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656 \
--hash=sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc \
--hash=sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518 \
--hash=sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56 \
--hash=sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc \
--hash=sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa \
--hash=sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565 \
--hash=sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4 \
--hash=sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb \
--hash=sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250 \
--hash=sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4 \
--hash=sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959 \
--hash=sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc \
--hash=sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474 \
--hash=sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863 \
--hash=sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8 \
--hash=sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f \
--hash=sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2 \
--hash=sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e \
--hash=sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e \
--hash=sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb \
--hash=sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f \
--hash=sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a \
--hash=sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26 \
--hash=sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d \
--hash=sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2 \
--hash=sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131 \
--hash=sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789 \
--hash=sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6 \
--hash=sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a \
--hash=sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858 \
--hash=sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e \
--hash=sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb \
--hash=sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e \
--hash=sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84 \
--hash=sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7 \
--hash=sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea \
--hash=sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b \
--hash=sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6 \
--hash=sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475 \
--hash=sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74 \
--hash=sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a \
--hash=sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00
# via jinja2
mdit-py-plugins==0.4.0 \
--hash=sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9 \
@ -224,9 +224,9 @@ pygments==2.17.2 \
--hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
--hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
# via sphinx
pytz==2023.3.post1 \
--hash=sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b \
--hash=sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7
pytz==2023.4 \
--hash=sha256:31d4583c4ed539cd037956140d695e42c033a19e984bfce9964a3f7d59bc2b40 \
--hash=sha256:f90ef520d95e7c46951105338d918664ebfd6f1d995bd7d153127ce90efafa6a
# via babel
pyyaml==6.0.1 \
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
@ -258,6 +258,7 @@ pyyaml==6.0.1 \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \

View File

@ -11,7 +11,7 @@ types-boto
types-chardet
types-decorator
types-jsonschema
types-Markdown<3.5.0.3 # https://github.com/python/typeshed/pull/10972#pullrequestreview-1760743552
types-Markdown
types-oauthlib
types-polib
types-pika

View File

@ -17,7 +17,7 @@ pip==20.3.4 \
--hash=sha256:217ae5161a0e08c0fb873858806e3478c9775caffce5168b50ec885e358c199d \
--hash=sha256:6773934e5f5fc3eaa8c5a44949b5b924fc122daa0a8aa9f80c835b4ca2a543fc
# via -r requirements/pip.in
setuptools==69.0.2 \
--hash=sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2 \
--hash=sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6
setuptools==69.0.3 \
--hash=sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05 \
--hash=sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78
# via -r requirements/pip.in

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
"""
Use libraries from a virtualenv (by modifying sys.path) in production.
"""
import os
import sys

View File

@ -186,8 +186,7 @@ class FilterType(Enum):
class FilterFunc(Protocol):
def __call__(self, m: Match[str], t: str = ...) -> bool:
...
def __call__(self, m: Match[str], t: str = ...) -> bool: ...
def main() -> None:

View File

@ -137,10 +137,10 @@ def run() -> None:
pass_targets=False,
description="Static type checker for Python (config: pyproject.toml)",
suppress_line=(
lambda line: line.startswith("Daemon") or line == "Restarting: configuration changed"
)
(lambda line: line.startswith("Daemon") or line == "Restarting: configuration changed")
if args.use_mypy_daemon
else lambda _: False,
else lambda _: False
),
)
linter_config.external_linter(
"ruff",

View File

@ -48,4 +48,4 @@ API_FEATURE_LEVEL = 237
# historical commits sharing the same major version, in which case a
# minor version bump suffices.
PROVISION_VERSION = (258, 0)
PROVISION_VERSION = (259, 0)

View File

@ -445,9 +445,9 @@ def do_update_message(
event["orig_rendered_content"] = target_message.rendered_content
edit_history_event["prev_content"] = target_message.content
edit_history_event["prev_rendered_content"] = target_message.rendered_content
edit_history_event[
"prev_rendered_content_version"
] = target_message.rendered_content_version
edit_history_event["prev_rendered_content_version"] = (
target_message.rendered_content_version
)
target_message.content = content
target_message.rendered_content = rendering_result.rendered_content
target_message.rendered_content_version = markdown_version
@ -848,16 +848,16 @@ def do_update_message(
if new_stream is not None and user_topic.user_profile_id in losing_access_user_ids:
stream_inaccessible_to_user_profiles.append(user_topic.user_profile)
else:
orig_topic_user_profile_to_visibility_policy[
user_topic.user_profile
] = user_topic.visibility_policy
orig_topic_user_profile_to_visibility_policy[user_topic.user_profile] = (
user_topic.visibility_policy
)
for user_topic in get_users_with_user_topic_visibility_policy(
target_stream.id, target_topic_name
):
target_topic_user_profile_to_visibility_policy[
user_topic.user_profile
] = user_topic.visibility_policy
target_topic_user_profile_to_visibility_policy[user_topic.user_profile] = (
user_topic.visibility_policy
)
# User profiles having any of the visibility policies set for either the original or target topic.
user_profiles_having_visibility_policy: Set[UserProfile] = set(
@ -867,18 +867,18 @@ def do_update_message(
)
)
user_profiles_for_visibility_policy_pair: Dict[
Tuple[int, int], List[UserProfile]
] = defaultdict(list)
user_profiles_for_visibility_policy_pair: Dict[Tuple[int, int], List[UserProfile]] = (
defaultdict(list)
)
for user_profile_with_policy in user_profiles_having_visibility_policy:
if user_profile_with_policy not in target_topic_user_profile_to_visibility_policy:
target_topic_user_profile_to_visibility_policy[
user_profile_with_policy
] = UserTopic.VisibilityPolicy.INHERIT
target_topic_user_profile_to_visibility_policy[user_profile_with_policy] = (
UserTopic.VisibilityPolicy.INHERIT
)
elif user_profile_with_policy not in orig_topic_user_profile_to_visibility_policy:
orig_topic_user_profile_to_visibility_policy[
user_profile_with_policy
] = UserTopic.VisibilityPolicy.INHERIT
orig_topic_user_profile_to_visibility_policy[user_profile_with_policy] = (
UserTopic.VisibilityPolicy.INHERIT
)
orig_topic_visibility_policy = orig_topic_user_profile_to_visibility_policy[
user_profile_with_policy

View File

@ -214,8 +214,7 @@ def build_subscription(recipient_id: int, user_id: int, subscription_id: int) ->
class GetUsers(Protocol):
def __call__(self, stream_id: int = ..., huddle_id: int = ...) -> Set[int]:
...
def __call__(self, stream_id: int = ..., huddle_id: int = ...) -> Set[int]: ...
def build_stream_subscriptions(

View File

@ -2,6 +2,7 @@
spec:
https://docs.mattermost.com/administration/bulk-export.html
"""
import logging
import os
import random

View File

@ -481,9 +481,9 @@ def do_login(request: HttpRequest, user_profile: UserProfile) -> None:
assert isinstance(validated_user_profile, UserProfile)
django_login(request, validated_user_profile)
RequestNotes.get_notes(
request
).requester_for_logs = validated_user_profile.format_requester_for_logs()
RequestNotes.get_notes(request).requester_for_logs = (
validated_user_profile.format_requester_for_logs()
)
process_client(request, validated_user_profile, is_browser_view=True)
if settings.TWO_FACTOR_AUTHENTICATION_ENABLED:
# Log in with two factor authentication as well.
@ -537,15 +537,13 @@ def human_users_only(
return _wrapped_view_func
# Based on Django 1.8's @login_required
@overload
def zulip_login_required(
function: Callable[Concatenate[HttpRequest, ParamT], HttpResponse],
redirect_field_name: str = REDIRECT_FIELD_NAME,
login_url: str = settings.HOME_NOT_LOGGED_IN,
) -> Callable[Concatenate[HttpRequest, ParamT], HttpResponse]:
...
) -> Callable[Concatenate[HttpRequest, ParamT], HttpResponse]: ...
@overload
def zulip_login_required(
function: None,
@ -554,11 +552,7 @@ def zulip_login_required(
) -> Callable[
[Callable[Concatenate[HttpRequest, ParamT], HttpResponse]],
Callable[Concatenate[HttpRequest, ParamT], HttpResponse],
]:
...
# Based on Django 1.8's @login_required
]: ...
def zulip_login_required(
function: Optional[Callable[Concatenate[HttpRequest, ParamT], HttpResponse]] = None,
redirect_field_name: str = REDIRECT_FIELD_NAME,

View File

@ -132,9 +132,11 @@ def der_encode_ticket(tkt: Dict[str, Any]) -> bytes:
der_encode_sequence( # EncryptedData
[
der_encode_int32(tkt["encPart"]["etype"]),
(
der_encode_uint32(tkt["encPart"]["kvno"])
if "kvno" in tkt["encPart"]
else None,
else None
),
der_encode_octet_string(base64.b64decode(tkt["encPart"]["cipher"])),
]
),

View File

@ -1,6 +1,7 @@
"""
Context managers, i.e. things you can use with the 'with' statement.
"""
import fcntl
from contextlib import contextmanager
from typing import IO, Any, Iterator, Union

View File

@ -661,9 +661,9 @@ def handle_missedmessage_emails(
unique_messages[m.id] = dict(
message=m,
trigger=message_info.trigger if message_info else None,
mentioned_user_group_id=message_info.mentioned_user_group_id
if message_info is not None
else None,
mentioned_user_group_id=(
message_info.mentioned_user_group_id if message_info is not None else None
),
)
do_send_missedmessage_events_reply_in_zulip(
user_profile,

View File

@ -350,9 +350,9 @@ def fetch_initial_state_data(
state["server_emoji_data_url"] = emoji.data_url()
state["server_needs_upgrade"] = is_outdated_server(user_profile)
state[
"event_queue_longpoll_timeout_seconds"
] = settings.EVENT_QUEUE_LONGPOLL_TIMEOUT_SECONDS
state["event_queue_longpoll_timeout_seconds"] = (
settings.EVENT_QUEUE_LONGPOLL_TIMEOUT_SECONDS
)
# TODO: This probably belongs on the server object.
state["realm_default_external_accounts"] = get_default_external_accounts()
@ -393,15 +393,15 @@ def fetch_initial_state_data(
state["server_presence_ping_interval_seconds"] = settings.PRESENCE_PING_INTERVAL_SECS
state["server_presence_offline_threshold_seconds"] = settings.OFFLINE_THRESHOLD_SECS
# Typing notifications protocol parameters for client behavior.
state[
"server_typing_started_expiry_period_milliseconds"
] = settings.TYPING_STARTED_EXPIRY_PERIOD_MILLISECONDS
state[
"server_typing_stopped_wait_period_milliseconds"
] = settings.TYPING_STOPPED_WAIT_PERIOD_MILLISECONDS
state[
"server_typing_started_wait_period_milliseconds"
] = settings.TYPING_STARTED_WAIT_PERIOD_MILLISECONDS
state["server_typing_started_expiry_period_milliseconds"] = (
settings.TYPING_STARTED_EXPIRY_PERIOD_MILLISECONDS
)
state["server_typing_stopped_wait_period_milliseconds"] = (
settings.TYPING_STOPPED_WAIT_PERIOD_MILLISECONDS
)
state["server_typing_started_wait_period_milliseconds"] = (
settings.TYPING_STARTED_WAIT_PERIOD_MILLISECONDS
)
state["server_supported_permission_settings"] = get_server_supported_permission_settings()
if want("realm_user_settings_defaults"):
@ -907,9 +907,9 @@ def apply_event(
# Recompute properties based on is_admin/is_guest
state["can_create_private_streams"] = user_profile.can_create_private_streams()
state["can_create_public_streams"] = user_profile.can_create_public_streams()
state[
"can_create_web_public_streams"
] = user_profile.can_create_web_public_streams()
state["can_create_web_public_streams"] = (
user_profile.can_create_web_public_streams()
)
state["can_create_streams"] = (
state["can_create_private_streams"]
or state["can_create_public_streams"]

View File

@ -1,6 +1,7 @@
"""
This module stores data for "external account" custom profile field.
"""
from dataclasses import dataclass
from typing import Dict

View File

@ -45,9 +45,11 @@ def generate_topics(num_topics: int) -> List[str]:
resolved_topic_probability = 0.05
return [
(
RESOLVED_TOPIC_PREFIX + topic_name
if random.random() < resolved_topic_probability
else topic_name
)
for topic_name in topic_names
]

View File

@ -570,13 +570,14 @@ class BacktickInlineProcessor(markdown.inlinepatterns.BacktickInlineProcessor):
@override
def handleMatch( # type: ignore[override] # https://github.com/python/mypy/issues/10197
self, m: Match[str], data: str
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
) -> Tuple[Union[Element, str, None], Optional[int], Optional[int]]:
# Let upstream's implementation do its job as it is, we'll
# just replace the text to not strip the group because it
# makes it impossible to put leading/trailing whitespace in
# an inline code span.
el, start, end = ret = super().handleMatch(m, data)
if el is not None and m.group(3):
assert isinstance(el, Element)
# upstream's code here is: m.group(3).strip() rather than m.group(3).
el.text = markdown.util.AtomicString(markdown.util.code_escape(m.group(3)))
return ret
@ -1492,7 +1493,7 @@ class UnicodeEmoji(CompiledInlineProcessor):
@override
def handleMatch( # type: ignore[override] # https://github.com/python/mypy/issues/10197
self, match: Match[str], data: str
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
) -> Tuple[Union[Element, str, None], Optional[int], Optional[int]]:
orig_syntax = match.group("syntax")
# We want to avoid turning things like arrows (↔) and keycaps (numbers
@ -1840,7 +1841,7 @@ class LinkifierPattern(CompiledInlineProcessor):
@override
def handleMatch( # type: ignore[override] # https://github.com/python/mypy/issues/10197
self, m: Match[str], data: str
) -> Union[Tuple[Element, int, int], Tuple[None, None, None]]:
) -> Tuple[Union[Element, str, None], Optional[int], Optional[int]]:
db_data: Optional[DbData] = self.zmd.zulip_db_data
url = url_to_a(
db_data,
@ -1861,7 +1862,7 @@ class UserMentionPattern(CompiledInlineProcessor):
@override
def handleMatch( # type: ignore[override] # https://github.com/python/mypy/issues/10197
self, m: Match[str], data: str
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
) -> Tuple[Union[Element, str, None], Optional[int], Optional[int]]:
name = m.group("match")
silent = m.group("silent") == "_"
db_data: Optional[DbData] = self.zmd.zulip_db_data
@ -1927,7 +1928,7 @@ class UserGroupMentionPattern(CompiledInlineProcessor):
@override
def handleMatch( # type: ignore[override] # https://github.com/python/mypy/issues/10197
self, m: Match[str], data: str
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
) -> Tuple[Union[Element, str, None], Optional[int], Optional[int]]:
name = m.group("match")
silent = m.group("silent") == "_"
db_data: Optional[DbData] = self.zmd.zulip_db_data
@ -1968,7 +1969,7 @@ class StreamPattern(CompiledInlineProcessor):
@override
def handleMatch( # type: ignore[override] # https://github.com/python/mypy/issues/10197
self, m: Match[str], data: str
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
) -> Tuple[Union[Element, str, None], Optional[int], Optional[int]]:
name = m.group("stream_name")
stream_id = self.find_stream_id(name)
@ -2000,7 +2001,7 @@ class StreamTopicPattern(CompiledInlineProcessor):
@override
def handleMatch( # type: ignore[override] # https://github.com/python/mypy/issues/10197
self, m: Match[str], data: str
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
) -> Tuple[Union[Element, str, None], Optional[int], Optional[int]]:
stream_name = m.group("stream_name")
topic_name = m.group("topic_name")
@ -2121,11 +2122,11 @@ class LinkInlineProcessor(markdown.inlinepatterns.LinkInlineProcessor):
@override
def handleMatch( # type: ignore[override] # https://github.com/python/mypy/issues/10197
self, m: Match[str], data: str
) -> Union[Tuple[None, None, None], Tuple[Element, int, int]]:
) -> Tuple[Union[Element, str, None], Optional[int], Optional[int]]:
ret = super().handleMatch(m, data)
if ret[0] is not None:
el: Optional[Element]
el, match_start, index = ret
assert isinstance(el, Element)
el = self.zulip_specific_link_changes(el)
if el is not None:
return el, match_start, index

View File

@ -75,6 +75,7 @@ Dependencies:
* [Pygments (optional)](http://pygments.org)
"""
import re
from typing import Any, Callable, Dict, Iterable, List, Mapping, MutableSequence, Optional, Sequence

View File

@ -664,9 +664,9 @@ class MessageDict:
if rendered_content is not None:
obj["rendered_content"] = rendered_content
else:
obj[
"rendered_content"
] = "<p>[Zulip note: Sorry, we could not understand the formatting of your message]</p>"
obj["rendered_content"] = (
"<p>[Zulip note: Sorry, we could not understand the formatting of your message]</p>"
)
if rendered_content is not None:
obj["is_me_message"] = Message.is_status_message(content, rendered_content)

View File

@ -130,8 +130,7 @@ def is_web_public_narrow(narrow: Optional[Iterable[Dict[str, Any]]]) -> bool:
class NarrowPredicate(Protocol):
def __call__(self, *, message: Dict[str, Any], flags: List[str]) -> bool:
...
def __call__(self, *, message: Dict[str, Any], flags: List[str]) -> bool: ...
def build_narrow_predicate(

View File

@ -17,6 +17,7 @@ from users:
And then on top of that, we want to represent narrow
specification internally as dataclasses.
"""
from dataclasses import dataclass
from typing import Collection, Sequence

View File

@ -50,5 +50,4 @@ class BaseNotes(Generic[_KeyT, _DataT], metaclass=ABCMeta):
@classmethod
@abstractmethod
def init_notes(cls) -> _DataT:
...
def init_notes(cls) -> _DataT: ...

View File

@ -291,9 +291,9 @@ def send_apple_push_notification(
if have_missing_app_id:
devices = [device for device in devices if device.ios_app_id is not None]
async def send_all_notifications() -> Iterable[
Tuple[DeviceToken, Union[aioapns.common.NotificationResult, BaseException]]
]:
async def send_all_notifications() -> (
Iterable[Tuple[DeviceToken, Union[aioapns.common.NotificationResult, BaseException]]]
):
requests = [
aioapns.NotificationRequest(
apns_topic=device.ios_app_id,

View File

@ -80,9 +80,9 @@ class QueueClient(Generic[ChannelT], metaclass=ABCMeta):
if self.rabbitmq_heartbeat == 0:
tcp_options = dict(TCP_KEEPIDLE=60 * 5)
ssl_options: Union[
Type[pika.ConnectionParameters._DEFAULT], pika.SSLOptions
] = pika.ConnectionParameters._DEFAULT
ssl_options: Union[Type[pika.ConnectionParameters._DEFAULT], pika.SSLOptions] = (
pika.ConnectionParameters._DEFAULT
)
if settings.RABBITMQ_USE_TLS:
ssl_options = pika.SSLOptions(context=ssl.create_default_context())
@ -313,9 +313,11 @@ class TornadoQueueClient(QueueClient[Channel]):
self._connection_failure_count += 1
retry_secs = self.CONNECTION_RETRY_SECS
self.log.log(
(
logging.CRITICAL
if self._connection_failure_count > self.CONNECTION_FAILURES_BEFORE_NOTIFY
else logging.WARNING,
else logging.WARNING
),
"TornadoQueueClient couldn't connect to RabbitMQ, retrying in %d secs...",
retry_secs,
)

View File

@ -222,8 +222,7 @@ def REQ(
documentation_pending: bool = ...,
aliases: Sequence[str] = ...,
path_only: bool = ...,
) -> ResultT:
...
) -> ResultT: ...
# Overload 2: json_validator
@ -238,8 +237,7 @@ def REQ(
documentation_pending: bool = ...,
aliases: Sequence[str] = ...,
path_only: bool = ...,
) -> ResultT:
...
) -> ResultT: ...
# Overload 3: no converter/json_validator, default: str or unspecified, argument_type=None
@ -253,8 +251,7 @@ def REQ(
documentation_pending: bool = ...,
aliases: Sequence[str] = ...,
path_only: bool = ...,
) -> str:
...
) -> str: ...
# Overload 4: no converter/validator, default=None, argument_type=None
@ -268,8 +265,7 @@ def REQ(
documentation_pending: bool = ...,
aliases: Sequence[str] = ...,
path_only: bool = ...,
) -> Optional[str]:
...
) -> Optional[str]: ...
# Overload 5: argument_type="body"
@ -283,8 +279,7 @@ def REQ(
documentation_pending: bool = ...,
aliases: Sequence[str] = ...,
path_only: bool = ...,
) -> ResultT:
...
) -> ResultT: ...
# Implementation

View File

@ -37,7 +37,7 @@ from django.http.request import QueryDict
from django.http.response import HttpResponseBase
from django.test import override_settings
from django.urls import URLResolver
from moto.s3 import mock_s3
from moto.core.decorator import mock_aws
from mypy_boto3_s3.service_resource import Bucket
from typing_extensions import ParamSpec, override
@ -562,7 +562,7 @@ P = ParamSpec("P")
def use_s3_backend(method: Callable[P, None]) -> Callable[P, None]:
@mock_s3
@mock_aws
@override_settings(LOCAL_UPLOADS_DIR=None)
@override_settings(LOCAL_AVATARS_DIR=None)
@override_settings(LOCAL_FILES_DIR=None)

View File

@ -10,7 +10,6 @@ import boto3
import botocore
from botocore.client import Config
from django.conf import settings
from mypy_boto3_s3 import S3Client
from mypy_boto3_s3.service_resource import Bucket, Object
from typing_extensions import override
@ -107,7 +106,7 @@ def upload_image_to_s3(
def get_signed_upload_url(path: str, force_download: bool = False) -> str:
client: S3Client = get_bucket(settings.S3_AUTH_UPLOADS_BUCKET).meta.client # type: ignore[assignment] # https://github.com/youtype/mypy_boto3_builder/issues/239
client = get_bucket(settings.S3_AUTH_UPLOADS_BUCKET).meta.client
params = {
"Bucket": settings.S3_AUTH_UPLOADS_BUCKET,
"Key": path,
@ -164,7 +163,7 @@ class S3UploadBackend(ZulipUploadBackend):
# We do not access self.avatar_bucket.meta.client directly,
# since that client is auth'd, and we want only the direct
# unauthed endpoint here.
client: S3Client = get_bucket(self.avatar_bucket.name, authed=False).meta.client # type: ignore[assignment] # https://github.com/youtype/mypy_boto3_builder/issues/239
client = get_bucket(self.avatar_bucket.name, authed=False).meta.client
dummy_signed_url = client.generate_presigned_url(
ClientMethod="get_object",
Params={

View File

@ -27,6 +27,7 @@ To extend this concept, it's simply a matter of writing your own validator
for any particular type of object.
"""
import re
import sys
from dataclasses import dataclass
@ -260,10 +261,7 @@ def check_dict(
optional_keys: Collection[Tuple[str, Validator[object]]] = [],
*,
_allow_only_listed_keys: bool = False,
) -> Validator[Dict[str, object]]:
...
) -> Validator[Dict[str, object]]: ...
@overload
def check_dict(
required_keys: Collection[Tuple[str, Validator[ResultT]]] = [],
@ -271,10 +269,7 @@ def check_dict(
*,
value_validator: Validator[ResultT],
_allow_only_listed_keys: bool = False,
) -> Validator[Dict[str, ResultT]]:
...
) -> Validator[Dict[str, ResultT]]: ...
def check_dict(
required_keys: Collection[Tuple[str, Validator[ResultT]]] = [],
optional_keys: Collection[Tuple[str, Validator[ResultT]]] = [],

View File

@ -4,6 +4,7 @@ various things (e.g. invitation reminders and welcome emails).
This management command is run via supervisor.
"""
import logging
import time
from typing import Any

View File

@ -17,6 +17,7 @@ We extract and validate the target stream from information in the
recipient address and retrieve, forward, and archive the message.
"""
import email
import email.policy
import logging

View File

@ -31,6 +31,7 @@ Credit for the approach goes to:
https://stackoverflow.com/questions/2090717
"""
import glob
import itertools
import json

View File

@ -136,9 +136,11 @@ To learn more about the test itself, see zerver/openapi/test_curl_examples.py.
file_name=file_name,
line=line,
curl_command=generated_curl_command,
response=response_json
response=(
response_json
if response is None
else json.dumps(response, indent=4),
else json.dumps(response, indent=4)
),
)
)
raise

View File

@ -70,9 +70,9 @@ class DecoratorTestCase(ZulipTestCase):
self.assertEqual(parse_client(req), ("Unspecified", None))
req = HostRequestMock()
req.META[
"HTTP_USER_AGENT"
] = "ZulipElectron/4.0.3 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Zulip/4.0.3 Chrome/66.0.3359.181 Electron/3.1.10 Safari/537.36"
req.META["HTTP_USER_AGENT"] = (
"ZulipElectron/4.0.3 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Zulip/4.0.3 Chrome/66.0.3359.181 Electron/3.1.10 Safari/537.36"
)
self.assertEqual(parse_client(req), ("ZulipElectron", "4.0.3"))
req = HostRequestMock()
@ -89,23 +89,23 @@ class DecoratorTestCase(ZulipTestCase):
# TODO: This should ideally be Firefox.
req = HostRequestMock()
req.META[
"HTTP_USER_AGENT"
] = "Mozilla/5.0 (X11; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0"
req.META["HTTP_USER_AGENT"] = (
"Mozilla/5.0 (X11; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0"
)
self.assertEqual(parse_client(req), ("Mozilla", None))
# TODO: This should ideally be Chrome.
req = HostRequestMock()
req.META[
"HTTP_USER_AGENT"
] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.43 Safari/537.36"
req.META["HTTP_USER_AGENT"] = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.43 Safari/537.36"
)
self.assertEqual(parse_client(req), ("Mozilla", None))
# TODO: This should ideally be Mobile Safari if we had better user-agent parsing.
req = HostRequestMock()
req.META[
"HTTP_USER_AGENT"
] = "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36"
req.META["HTTP_USER_AGENT"] = (
"Mozilla/5.0 (Linux; Android 8.0.0; SM-G930F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36"
)
self.assertEqual(parse_client(req), ("Mozilla", None))
post_req_with_client = HostRequestMock()

View File

@ -490,9 +490,9 @@ and other things
incoming_valid_message = EmailMessage()
incoming_valid_message.set_content("TestStreamEmailMessages body")
incoming_valid_message["Subject"] = "TestStreamEmailMessages subject"
incoming_valid_message[
"From"
] = "Test =?utf-8?b?VXNlcsOzxIXEmQ==?= <=?utf-8?q?hamlet=5F=C4=99?=@zulip.com>"
incoming_valid_message["From"] = (
"Test =?utf-8?b?VXNlcsOzxIXEmQ==?= <=?utf-8?q?hamlet=5F=C4=99?=@zulip.com>"
)
incoming_valid_message["To"] = stream_to_address
incoming_valid_message["Reply-to"] = self.example_email("othello")

View File

@ -744,9 +744,11 @@ class PreviewTestCase(ZulipTestCase):
# HTML with a bad og:image metadata
html = "\n".join(
(
line
if "og:image" not in line
else '<meta property="og:image" content="http://[bad url/" />'
)
for line in self.open_graph_html.splitlines()
)
self.create_mock_response(url, body=html)

View File

@ -1180,7 +1180,7 @@ class TestMessageNotificationEmails(ZulipTestCase):
f"http://zulip.testserver/user_avatars/{realm.id}/emoji/images/{realm_emoji_id}.png"
)
verify_body_include = [
f'<img alt=":green_tick:" src="{realm_emoji_url}" style="height: 20px;" title="green tick">'
f'<img alt=":green_tick:" src="{realm_emoji_url}" title="green tick" style="height: 20px;">'
]
email_subject = "DMs with Othello, the Moor of Venice"
self._test_cases(
@ -1200,7 +1200,7 @@ class TestMessageNotificationEmails(ZulipTestCase):
"Extremely personal message with a hamburger :hamburger:!",
)
verify_body_include = [
'<img alt=":hamburger:" src="http://testserver/static/generated/emoji/images-twitter-64/1f354.png" style="height: 20px;" title="hamburger">'
'<img alt=":hamburger:" src="http://testserver/static/generated/emoji/images-twitter-64/1f354.png" title="hamburger" style="height: 20px;">'
]
email_subject = "DMs with Othello, the Moor of Venice"
self._test_cases(
@ -1219,7 +1219,7 @@ class TestMessageNotificationEmails(ZulipTestCase):
stream_id = get_stream("Verona", get_realm("zulip")).id
href = f"http://zulip.testserver/#narrow/stream/{stream_id}-Verona"
verify_body_include = [
f'<a class="stream" data-stream-id="{stream_id}" href="{href}">#Verona</a'
f'<a class="stream" href="{href}" data-stream-id="{stream_id}">#Verona</a'
]
email_subject = "DMs with Othello, the Moor of Venice"
self._test_cases(

View File

@ -78,9 +78,9 @@ class RealmFilterTest(ZulipTestCase):
self.assertIsNotNone(re.match(data["pattern"], "_code=123abcdZ"))
data["pattern"] = r"PR (?P<id>[0-9]+)"
data[
"url_template"
] = "https://example.com/~user/web#view_type=type&model=model&action=12345&id={id}"
data["url_template"] = (
"https://example.com/~user/web#view_type=type&model=model&action=12345&id={id}"
)
result = self.client_post("/json/realm/filters", info=data)
self.assert_json_success(result)
self.assertIsNotNone(re.match(data["pattern"], "PR 123"))
@ -141,12 +141,12 @@ class RealmFilterTest(ZulipTestCase):
self.assert_json_success(result)
self.assertIsNotNone(re.match(data["pattern"], "zulip/zulip#123"))
data[
"pattern"
] = r"FOO_(?P<id>[a-f]{5});(?P<zone>[a-f]);(?P<domain>[a-z]+);(?P<location>[a-z]+);(?P<name>[a-z]{2,8});(?P<chapter>[0-9]{2,3});(?P<fragment>[a-z]{2,8})"
data[
"url_template"
] = "https://zone_{zone}{.domain}.net/ticket{/location}{/id}{?name,chapter}{#fragment:5}"
data["pattern"] = (
r"FOO_(?P<id>[a-f]{5});(?P<zone>[a-f]);(?P<domain>[a-z]+);(?P<location>[a-z]+);(?P<name>[a-z]{2,8});(?P<chapter>[0-9]{2,3});(?P<fragment>[a-z]{2,8})"
)
data["url_template"] = (
"https://zone_{zone}{.domain}.net/ticket{/location}{/id}{?name,chapter}{#fragment:5}"
)
result = self.client_post("/json/realm/filters", info=data)
self.assert_json_success(result)

View File

@ -2,7 +2,7 @@ import os
from unittest.mock import Mock, patch
from django.conf import settings
from moto.s3 import mock_s3
from moto.core.decorator import mock_aws
from zerver.actions.realm_emoji import check_add_realm_emoji
from zerver.lib.avatar_hash import user_avatar_path
@ -35,7 +35,7 @@ class TransferUploadsToS3Test(ZulipTestCase):
m2.assert_called_with(4)
m3.assert_called_with(4)
@mock_s3
@mock_aws
def test_transfer_avatars_to_s3(self) -> None:
bucket = create_s3_buckets(settings.S3_AVATAR_BUCKET)[0]
@ -61,7 +61,7 @@ class TransferUploadsToS3Test(ZulipTestCase):
with open(avatar_disk_path(user, medium=True), "rb") as f:
self.assertEqual(medium_image_key.get()["Body"].read(), f.read())
@mock_s3
@mock_aws
def test_transfer_message_files(self) -> None:
bucket = create_s3_buckets(settings.S3_AUTH_UPLOADS_BUCKET)[0]
hamlet = self.example_user("hamlet")
@ -79,7 +79,7 @@ class TransferUploadsToS3Test(ZulipTestCase):
self.assertEqual(bucket.Object(attachments[0].path_id).get()["Body"].read(), b"zulip1!")
self.assertEqual(bucket.Object(attachments[1].path_id).get()["Body"].read(), b"zulip2!")
@mock_s3
@mock_aws
def test_transfer_emoji_to_s3(self) -> None:
bucket = create_s3_buckets(settings.S3_AVATAR_BUCKET)[0]
othello = self.example_user("othello")

View File

@ -50,8 +50,7 @@ class TestEndpoint(ZulipTestCase):
def test_coerce(self) -> None:
@typed_endpoint
def view(request: HttpRequest, *, strict_int: int) -> None:
...
def view(request: HttpRequest, *, strict_int: int) -> None: ...
with self.assertRaisesMessage(JsonableError, "strict_int is not an integer"):
call_endpoint(view, HostRequestMock({"strict_int": orjson.dumps("10").decode()}))
@ -322,8 +321,7 @@ class TestEndpoint(ZulipTestCase):
request: HttpRequest,
*,
path_var_default: PathOnly[str] = "test",
) -> None:
...
) -> None: ...
with self.assertRaisesMessage(
AssertionError, "Path-only parameter path_var_default should not have a default value"
@ -346,8 +344,7 @@ class TestEndpoint(ZulipTestCase):
],
paz: PathOnly[int],
other: str,
) -> None:
...
) -> None: ...
from zerver.lib.request import arguments_map
@ -365,16 +362,14 @@ class TestEndpoint(ZulipTestCase):
Json[int],
ApiParamConfig(path_only=True),
],
) -> None:
...
) -> None: ...
def annotated_with_repeated_api_param_config(
request: HttpRequest,
user_profile: UserProfile,
*,
foo: Annotated[Json[int], ApiParamConfig(), ApiParamConfig()],
) -> None:
...
) -> None: ...
with self.assertRaisesMessage(
AssertionError, "ApiParamConfig can only be defined once per parameter"
@ -408,8 +403,7 @@ class TestEndpoint(ZulipTestCase):
StringConstraints(strip_whitespace=True, max_length=3),
ApiParamConfig("test"),
] = None,
) -> None:
...
) -> None: ...
with self.assertRaisesMessage(ApiParamValidationError, "test is too long"):
call_endpoint(no_nesting, HostRequestMock({"test": "long"}))
@ -510,11 +504,9 @@ class TestEndpoint(ZulipTestCase):
)
def test_expect_no_parameters(self) -> None:
def no_parameter(request: HttpRequest) -> None:
...
def no_parameter(request: HttpRequest) -> None: ...
def has_parameters(request: HttpRequest, *, foo: int, bar: str) -> None:
...
def has_parameters(request: HttpRequest, *, foo: int, bar: str) -> None: ...
with self.assertRaisesRegex(AssertionError, "there is no keyword-only parameter found"):
typed_endpoint(no_parameter)
@ -551,13 +543,11 @@ class TestEndpoint(ZulipTestCase):
# all. The only possible way for val to be None is through the default
# value (if it has one).
@typed_endpoint
def foo(request: HttpRequest, *, val: Optional[Json[int]]) -> None:
...
def foo(request: HttpRequest, *, val: Optional[Json[int]]) -> None: ...
# Json[Optional[int]] however, allows client specified None value.
@typed_endpoint
def bar(request: HttpRequest, *, val: Json[Optional[int]]) -> None:
...
def bar(request: HttpRequest, *, val: Json[Optional[int]]) -> None: ...
with self.assertRaisesMessage(ApiParamValidationError, "val is not an integer"):
call_endpoint(foo, HostRequestMock({"val": orjson.dumps(None).decode()}))
@ -640,8 +630,7 @@ class ValidationErrorHandlingTest(ZulipTestCase):
input_type: Any = subtest.param_type
@typed_endpoint
def func(request: HttpRequest, *, input: input_type) -> None:
...
def func(request: HttpRequest, *, input: input_type) -> None: ...
with self.assertRaises(ApiParamValidationError) as m:
call_endpoint(func, HostRequestMock({"input": subtest.input_data}))

View File

@ -90,9 +90,9 @@ def accounts_accept_terms(request: HttpRequest) -> HttpResponse:
request.user.tos_version == UserProfile.TOS_VERSION_BEFORE_FIRST_LOGIN
and settings.FIRST_TIME_TERMS_OF_SERVICE_TEMPLATE is not None
):
context[
"first_time_terms_of_service_message_template"
] = settings.FIRST_TIME_TERMS_OF_SERVICE_TEMPLATE
context["first_time_terms_of_service_message_template"] = (
settings.FIRST_TIME_TERMS_OF_SERVICE_TEMPLATE
)
return render(
request,

View File

@ -247,9 +247,9 @@ def send_message_backend(
)
data["id"] = sent_message_result.message_id
if sent_message_result.automatic_new_visibility_policy:
data[
"automatic_new_visibility_policy"
] = sent_message_result.automatic_new_visibility_policy
data["automatic_new_visibility_policy"] = (
sent_message_result.automatic_new_visibility_policy
)
return json_success(request, data=data)

View File

@ -288,9 +288,9 @@ def update_realm(
)
if setting_value_changed:
data[
"move_messages_within_stream_limit_seconds"
] = move_messages_within_stream_limit_seconds
data["move_messages_within_stream_limit_seconds"] = (
move_messages_within_stream_limit_seconds
)
move_messages_between_streams_limit_seconds: Optional[int] = None
if move_messages_between_streams_limit_seconds_raw is not None:
@ -305,9 +305,9 @@ def update_realm(
)
if setting_value_changed:
data[
"move_messages_between_streams_limit_seconds"
] = move_messages_between_streams_limit_seconds
data["move_messages_between_streams_limit_seconds"] = (
move_messages_between_streams_limit_seconds
)
jitsi_server_url: Optional[str] = None
if jitsi_server_url_raw is not None:

View File

@ -188,9 +188,8 @@ def reactivate_user_backend(
return json_success(request)
check_profile_data: Validator[
List[Dict[str, Optional[Union[int, ProfileDataElementValue]]]]
] = check_list(
check_profile_data: Validator[List[Dict[str, Optional[Union[int, ProfileDataElementValue]]]]] = (
check_list(
check_dict_only(
[
("id", check_int),
@ -202,6 +201,7 @@ check_profile_data: Validator[
),
]
),
)
)

View File

@ -24,9 +24,11 @@ def api_bitbucket_webhook(
commits = [
{
"name": commit["author"].tame(check_string)
"name": (
commit["author"].tame(check_string)
if "author" in commit
else payload.get("user", "Someone").tame(check_string),
else payload.get("user", "Someone").tame(check_string)
),
"sha": commit["raw_node"].tame(check_string),
"message": commit["message"].tame(check_string),
"url": "{}{}commits/{}".format(

View File

@ -201,8 +201,7 @@ def get_type(request: HttpRequest, payload: WildValue) -> str:
class BodyGetter(Protocol):
def __call__(self, request: HttpRequest, payload: WildValue, include_title: bool) -> str:
...
def __call__(self, request: HttpRequest, payload: WildValue, include_title: bool) -> str: ...
def get_body_based_on_type(
@ -372,12 +371,16 @@ def get_pull_request_created_or_updated_body(
action=action,
url=get_pull_request_url(pull_request),
number=pull_request["id"].tame(check_int),
target_branch=pull_request["source"]["branch"]["name"].tame(check_string)
target_branch=(
pull_request["source"]["branch"]["name"].tame(check_string)
if action == "created"
else None,
base_branch=pull_request["destination"]["branch"]["name"].tame(check_string)
else None
),
base_branch=(
pull_request["destination"]["branch"]["name"].tame(check_string)
if action == "created"
else None,
else None
),
message=pull_request["description"].tame(check_string),
assignee=assignee,
title=pull_request["title"].tame(check_string) if include_title else None,

View File

@ -393,8 +393,7 @@ def pr_comment_handler(
class EventHandler(Protocol):
def __call__(
self, payload: WildValue, branches: Optional[str], include_title: Optional[str]
) -> List[Dict[str, str]]:
...
) -> List[Dict[str, str]]: ...
EVENT_HANDLER_MAP: Dict[str, EventHandler] = {

View File

@ -398,9 +398,11 @@ def get_story_create_github_entity_body(payload: WildValue, action: WildValue, e
name=action["name"].tame(check_string),
app_url=action["app_url"].tame(check_string),
),
"name": pull_request_action["number"].tame(check_int)
"name": (
pull_request_action["number"].tame(check_int)
if entity in ("pull-request", "pull-request-comment")
else pull_request_action["name"].tame(check_string),
else pull_request_action["name"].tame(check_string)
),
"url": pull_request_action["url"].tame(check_string),
"workflow_state_template": "",
}

View File

@ -1,4 +1,5 @@
"""Webhooks for external integrations."""
from typing import List
from django.http import HttpRequest, HttpResponse

View File

@ -160,9 +160,11 @@ def get_issue_body(helper: Helper) -> str:
action=action,
url=issue["html_url"].tame(check_string),
number=issue["number"].tame(check_int),
message=None
message=(
None
if action in ("assigned", "unassigned")
else issue["body"].tame(check_none_or(check_string)),
else issue["body"].tame(check_none_or(check_string))
),
title=issue["title"].tame(check_string) if include_title else None,
)

View File

@ -163,12 +163,12 @@ def get_merge_request_open_or_updated_body(
action=action,
url=pull_request["url"].tame(check_string),
number=pull_request["iid"].tame(check_int),
target_branch=pull_request["source_branch"].tame(check_string)
if action == "created"
else None,
base_branch=pull_request["target_branch"].tame(check_string)
if action == "created"
else None,
target_branch=(
pull_request["source_branch"].tame(check_string) if action == "created" else None
),
base_branch=(
pull_request["target_branch"].tame(check_string) if action == "created" else None
),
message=pull_request["description"].tame(check_none_or(check_string)),
assignees=replace_assignees_username_with_name(get_assignees(payload)),
type="MR",
@ -379,8 +379,7 @@ def get_object_url(payload: WildValue) -> str:
class EventFunction(Protocol):
def __call__(self, payload: WildValue, include_title: bool) -> str:
...
def __call__(self, payload: WildValue, include_title: bool) -> str: ...
EVENT_FUNCTION_MAPPER: Dict[str, EventFunction] = {
@ -467,9 +466,11 @@ def get_topic_based_on_event(event: str, payload: WildValue, use_merge_request_t
repo=get_repo_name(payload),
type="MR",
id=payload["object_attributes"]["iid"].tame(check_int),
title=payload["object_attributes"]["title"].tame(check_string)
title=(
payload["object_attributes"]["title"].tame(check_string)
if use_merge_request_title
else "",
else ""
),
)
elif event.startswith(("Issue Hook", "Confidential Issue Hook")):
return TOPIC_WITH_PR_OR_ISSUE_INFO_TEMPLATE.format(
@ -490,9 +491,11 @@ def get_topic_based_on_event(event: str, payload: WildValue, use_merge_request_t
repo=get_repo_name(payload),
type="MR",
id=payload["merge_request"]["iid"].tame(check_int),
title=payload["merge_request"]["title"].tame(check_string)
title=(
payload["merge_request"]["title"].tame(check_string)
if use_merge_request_title
else "",
else ""
),
)
elif event == "Note Hook Snippet":

View File

@ -173,8 +173,7 @@ def api_gogs_webhook(
class FormatPullRequestEvent(Protocol):
def __call__(self, payload: WildValue, include_title: bool) -> str:
...
def __call__(self, payload: WildValue, include_title: bool) -> str: ...
def gogs_webhook_main(

View File

@ -1,4 +1,5 @@
"""Webhooks for external integrations."""
import re
from typing import Any, Dict, List, Optional, Tuple

View File

@ -6,6 +6,7 @@ Tips for notification output:
value should always be in bold; otherwise the subject of US/task
should be in bold.
"""
from typing import Dict, List, Optional, Tuple, Union
from django.http import HttpRequest, HttpResponse

View File

@ -966,7 +966,9 @@ class Command(BaseCommand):
zulip_stream_dict: Dict[str, Dict[str, Any]] = {
"devel": {"description": "For developing"},
# ビデオゲーム - VideoGames (japanese)
"ビデオゲーム": {"description": f"Share your favorite video games! {raw_emojis[2]}"},
"ビデオゲーム": {
"description": f"Share your favorite video games! {raw_emojis[2]}"
},
"announce": {
"description": "For announcements",
"stream_post_policy": Stream.STREAM_POST_POLICY_ADMINS,

View File

@ -23,17 +23,11 @@ else:
@overload
def get_secret(key: str, default_value: str, development_only: bool = False) -> str:
...
def get_secret(key: str, default_value: str, development_only: bool = False) -> str: ...
@overload
def get_secret(
key: str, default_value: Optional[str] = None, development_only: bool = False
) -> Optional[str]:
...
) -> Optional[str]: ...
def get_secret(
key: str, default_value: Optional[str] = None, development_only: bool = False
) -> Optional[str]:
@ -52,15 +46,9 @@ def get_mandatory_secret(key: str) -> str:
@overload
def get_config(section: str, key: str, default_value: str) -> str:
...
def get_config(section: str, key: str, default_value: str) -> str: ...
@overload
def get_config(section: str, key: str, default_value: Optional[str] = None) -> Optional[str]:
...
def get_config(section: str, key: str, default_value: Optional[str] = None) -> Optional[str]: ...
def get_config(section: str, key: str, default_value: Optional[str] = None) -> Optional[str]:
return config_file.get(section, key, fallback=default_value)

View File

@ -13,6 +13,7 @@ middleware here, or combine a Django application with an application of another
framework.
"""
import os
import sys