ruff: Fix ISC003 Explicitly concatenated string.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2023-01-02 17:16:53 -08:00 committed by Tim Abbott
parent 2c5e114f8b
commit 17300f196c
28 changed files with 196 additions and 146 deletions

View File

@ -45,8 +45,10 @@ VNU_IGNORE = [
r"The first occurrence of ID “[^”]*” was here\.", r"The first occurrence of ID “[^”]*” was here\.",
r"Attribute “markdown” not allowed on element “div” at this point\.", r"Attribute “markdown” not allowed on element “div” at this point\.",
r"No “p” element in scope but a “p” end tag seen\.", r"No “p” element in scope but a “p” end tag seen\.",
r"Element “div” not allowed as child of element “ul” in this context\. " (
+ r"\(Suppressing further errors from this subtree\.\)", r"Element “div” not allowed as child of element “ul” in this context\."
r" \(Suppressing further errors from this subtree\.\)"
),
# Opinionated informational messages. # Opinionated informational messages.
r"Self-closing tag syntax in text/html documents is widely discouraged; its unnecessary and interacts badly with other HTML features \(e\.g\., unquoted attribute values\)\. If youre using a tool that injects self-closing tag syntax into all void elements, without any option to prevent it from doing so, then consider switching to a different tool\.", r"Self-closing tag syntax in text/html documents is widely discouraged; its unnecessary and interacts badly with other HTML features \(e\.g\., unquoted attribute values\)\. If youre using a tool that injects self-closing tag syntax into all void elements, without any option to prevent it from doing so, then consider switching to a different tool\.",
] ]

View File

@ -673,9 +673,7 @@ html_rules: List["Rule"] = [
{ {
"pattern": "style ?=", "pattern": "style ?=",
"description": "Avoid using the `style=` attribute; we prefer styling in CSS files", "description": "Avoid using the `style=` attribute; we prefer styling in CSS files",
"exclude_pattern": r'.*style ?=["' "exclude_pattern": r""".*style ?=["'](display: ?none|background: {{|color: {{|background-color: {{).*""",
+ "'"
+ "](display: ?none|background: {{|color: {{|background-color: {{).*",
"exclude": { "exclude": {
# 5xx page doesn't have external CSS # 5xx page doesn't have external CSS
"static/html/5xx.html", "static/html/5xx.html",

View File

@ -52,15 +52,15 @@ if settings.BILLING_ENABLED:
# We don't mark this error for translation, because it's displayed # We don't mark this error for translation, because it's displayed
# only to MIT users. # only to MIT users.
MIT_VALIDATION_ERROR = ( MIT_VALIDATION_ERROR = (
"That user does not exist at MIT or is a " "That user does not exist at MIT or is a"
+ '<a href="https://ist.mit.edu/email-lists">mailing list</a>. ' ' <a href="https://ist.mit.edu/email-lists">mailing list</a>.'
+ "If you want to sign up an alias for Zulip, " " If you want to sign up an alias for Zulip,"
+ '<a href="mailto:support@zulip.com">contact us</a>.' ' <a href="mailto:support@zulip.com">contact us</a>.'
) )
DEACTIVATED_ACCOUNT_ERROR = gettext_lazy( DEACTIVATED_ACCOUNT_ERROR = gettext_lazy(
"Your account {username} has been deactivated. " "Your account {username} has been deactivated."
+ "Please contact your organization administrator to reactivate it." " Please contact your organization administrator to reactivate it."
) )
PASSWORD_TOO_WEAK_ERROR = gettext_lazy("The password is too weak.") PASSWORD_TOO_WEAK_ERROR = gettext_lazy("The password is too weak.")
@ -451,9 +451,9 @@ class OurAuthenticationForm(AuthenticationForm):
assert e.secs_to_freedom is not None assert e.secs_to_freedom is not None
secs_to_freedom = int(e.secs_to_freedom) secs_to_freedom = int(e.secs_to_freedom)
error_message = _( error_message = _(
"You're making too many attempts to sign in. " "You're making too many attempts to sign in."
+ "Try again in {} seconds or contact your organization administrator " " Try again in {} seconds or contact your organization administrator"
+ "for help." " for help."
) )
raise ValidationError(error_message.format(secs_to_freedom)) raise ValidationError(error_message.format(secs_to_freedom))

View File

@ -163,9 +163,8 @@ server via `ps -ef` or reading bash history. Prefer
return UserProfile.objects.select_related().get(delivery_email__iexact=email.strip()) return UserProfile.objects.select_related().get(delivery_email__iexact=email.strip())
except MultipleObjectsReturned: except MultipleObjectsReturned:
raise CommandError( raise CommandError(
"This Zulip server contains multiple users with that email " "This Zulip server contains multiple users with that email (in different realms);"
+ "(in different realms); please pass `--realm` " " please pass `--realm` to specify which one to modify."
"to specify which one to modify."
) )
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
raise CommandError(f"This Zulip server does not contain a user with email '{email}'") raise CommandError(f"This Zulip server does not contain a user with email '{email}'")

View File

@ -849,8 +849,8 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
schema_re = r"(?:https?://)" schema_re = r"(?:https?://)"
host_re = r"(?:youtu\.be/|(?:\w+\.)?youtube(?:-nocookie)?\.com/)" host_re = r"(?:youtu\.be/|(?:\w+\.)?youtube(?:-nocookie)?\.com/)"
param_re = ( param_re = (
r"(?:(?:(?:v|embed)/)|" r"(?:(?:(?:v|embed)/)"
+ r"(?:(?:(?:watch|playlist)(?:_popup|_videos)?(?:\.php)?)?(?:\?|#!?)(?:.+&)?v(?:ideo_ids)?=))" r"|(?:(?:(?:watch|playlist)(?:_popup|_videos)?(?:\.php)?)?(?:\?|#!?)(?:.+&)?v(?:ideo_ids)?=))"
) )
id_re = r"([0-9A-Za-z_-]+)" id_re = r"([0-9A-Za-z_-]+)"
youtube_re = r"^({schema_re}?{host_re}{param_re}?)?{id_re}(?(1).+)?$" youtube_re = r"^({schema_re}?{host_re}{param_re}?)?{id_re}(?(1).+)?$"
@ -883,8 +883,8 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
vimeo_re = ( vimeo_re = (
r"^((http|https)?:\/\/(www\.)?vimeo.com\/" r"^((http|https)?:\/\/(www\.)?vimeo.com\/"
+ r"(?:channels\/(?:\w+\/)?|groups\/" r"(?:channels\/(?:\w+\/)?|groups\/"
+ r"([^\/]*)\/videos\/|)(\d+)(?:|\/\?))$" r"([^\/]*)\/videos\/|)(\d+)(?:|\/\?))$"
) )
match = re.match(vimeo_re, url) match = re.match(vimeo_re, url)
if match is None: if match is None:

View File

@ -194,7 +194,7 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
# Directly using `###` for subheading causes errors so use h3 with made up id. # Directly using `###` for subheading causes errors so use h3 with made up id.
argument_template = ( argument_template = (
'<div class="api-argument"><p class="api-argument-name"><h3 id="{h3_id}">' '<div class="api-argument"><p class="api-argument-name"><h3 id="{h3_id}">'
+ " {event_type} {op}</h3></p></div> \n{description}\n\n\n" "{event_type} {op}</h3></p></div> \n{description}\n\n\n"
) )
for events in events_dict["oneOf"]: for events in events_dict["oneOf"]:
event_type: Dict[str, Any] = events["properties"]["type"] event_type: Dict[str, Any] = events["properties"]["type"]

View File

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

View File

@ -74,7 +74,7 @@ def send_initial_pms(user: UserProfile) -> None:
_( _(
"If you are new to Zulip, check out our [Getting started guide]({getting_started_url})!" "If you are new to Zulip, check out our [Getting started guide]({getting_started_url})!"
), ),
"{organization_setup_text}" + "\n\n", "{organization_setup_text}\n\n",
"{demo_org_warning}", "{demo_org_warning}",
_( _(
"I can also help you get set up! Just click anywhere on this message or press `r` to reply." "I can also help you get set up! Just click anywhere on this message or press `r` to reply."

View File

@ -226,9 +226,9 @@ Output:
else: else:
# A web app request; use a browser User-Agent string. # A web app request; use a browser User-Agent string.
default_user_agent = ( default_user_agent = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
+ "AppleWebKit/537.36 (KHTML, like Gecko) " " AppleWebKit/537.36 (KHTML, like Gecko)"
+ "Chrome/79.0.3945.130 Safari/537.36" " Chrome/79.0.3945.130 Safari/537.36"
) )
if skip_user_agent: if skip_user_agent:
# Provide a way to disable setting User-Agent if desired. # Provide a way to disable setting User-Agent if desired.

View File

@ -307,16 +307,14 @@ def generate_curl_example(
authentication_required = True authentication_required = True
else: else:
raise AssertionError( raise AssertionError(
"Unhandled global securityScheme." "Unhandled global securityScheme. Please update the code to handle this scheme."
+ " Please update the code to handle this scheme."
) )
elif operation_security == []: elif operation_security == []:
if operation in insecure_operations: if operation in insecure_operations:
authentication_required = False authentication_required = False
else: else:
raise AssertionError( raise AssertionError(
"Unknown operation without a securityScheme. " "Unknown operation without a securityScheme. Please update insecure_operations."
+ "Please update insecure_operations."
) )
else: else:
raise AssertionError( raise AssertionError(

View File

@ -496,8 +496,8 @@ def validate_schema(schema: Dict[str, Any]) -> None:
elif schema["type"] == "object": elif schema["type"] == "object":
if "additionalProperties" not in schema: if "additionalProperties" not in schema:
raise SchemaError( raise SchemaError(
"additionalProperties needs to be defined for objects to make " "additionalProperties needs to be defined for objects to make sure they have no"
+ "sure they have no additional properties left to be documented." " additional properties left to be documented."
) )
for property_schema in schema.get("properties", {}).values(): for property_schema in schema.get("properties", {}).values():
validate_schema(property_schema) validate_schema(property_schema)

View File

@ -2000,15 +2000,15 @@ class SAMLAuthBackendTest(SocialAuthBase):
extra_attrs = "" extra_attrs = ""
for extra_attr_name, extra_attr_values in extra_attributes.items(): for extra_attr_name, extra_attr_values in extra_attributes.items():
values = "".join( values = "".join(
'<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" ' '<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"'
+ 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">' ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">'
+ f"{value}</saml2:AttributeValue>" f"{value}</saml2:AttributeValue>"
for value in extra_attr_values for value in extra_attr_values
) )
extra_attrs += ( extra_attrs += (
f'<saml2:Attribute Name="{extra_attr_name}" ' f'<saml2:Attribute Name="{extra_attr_name}"'
+ 'NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">' ' NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">'
+ f"{values}</saml2:Attribute>" f"{values}</saml2:Attribute>"
) )
unencoded_saml_response = self.fixture_data("samlresponse.txt", type="saml").format( unencoded_saml_response = self.fixture_data("samlresponse.txt", type="saml").format(
@ -2815,8 +2815,11 @@ class SAMLAuthBackendTest(SocialAuthBase):
m.output, m.output,
[ [
self.logger_output( self.logger_output(
"AuthFailed: Authentication failed: SAML user from IdP test_idp rejected due to " (
+ "missing entitlement for subdomain ''. User entitlements: ['zephyr'].", "AuthFailed: Authentication failed: SAML user from IdP test_idp"
" rejected due to missing entitlement for subdomain ''. User"
" entitlements: ['zephyr']."
),
"info", "info",
) )
], ],
@ -2839,8 +2842,11 @@ class SAMLAuthBackendTest(SocialAuthBase):
m.output, m.output,
[ [
self.logger_output( self.logger_output(
"AuthFailed: Authentication failed: SAML user from IdP test_idp rejected due to " (
+ "missing entitlement for subdomain 'zulip'. User entitlements: ['zephyr', 'othersubdomain'].", "AuthFailed: Authentication failed: SAML user from IdP test_idp rejected"
" due to missing entitlement for subdomain 'zulip'. User entitlements:"
" ['zephyr', 'othersubdomain']."
),
"info", "info",
) )
], ],
@ -2934,8 +2940,10 @@ class SAMLAuthBackendTest(SocialAuthBase):
m.output, m.output,
[ [
self.logger_output( self.logger_output(
"Exception while syncing custom profile fields for " (
+ f"user {self.user_profile.id}: Custom profile field with name title not found.", "Exception while syncing custom profile fields for user"
f" {self.user_profile.id}: Custom profile field with name title not found."
),
"warning", "warning",
) )
], ],

View File

@ -118,7 +118,7 @@ class BotTest(ZulipTestCase, UploadSerializeMixin):
error_message = ( error_message = (
"Can't create bots until FAKE_EMAIL_DOMAIN is correctly configured.\n" "Can't create bots until FAKE_EMAIL_DOMAIN is correctly configured.\n"
+ "Please contact your server administrator." "Please contact your server administrator."
) )
self.assert_json_error(result, error_message) self.assert_json_error(result, error_message)
self.assert_num_bots_equal(0) self.assert_num_bots_equal(0)

View File

@ -1451,7 +1451,7 @@ class TestMissedMessages(ZulipTestCase):
actual_output = convert(test_data) actual_output = convert(test_data)
expected_output = ( expected_output = (
'<div><a href="http://example.com/user_uploads/{realm_id}/1f/some_random_value">' '<div><a href="http://example.com/user_uploads/{realm_id}/1f/some_random_value">'
+ "/user_uploads/{realm_id}/1f/some_random_value</a></div>" "/user_uploads/{realm_id}/1f/some_random_value</a></div>"
) )
expected_output = expected_output.format(realm_id=zephyr_realm.id) expected_output = expected_output.format(realm_id=zephyr_realm.id)
self.assertEqual(actual_output, expected_output) self.assertEqual(actual_output, expected_output)
@ -1465,27 +1465,31 @@ class TestMissedMessages(ZulipTestCase):
# A narrow URL which begins with a '#'. # A narrow URL which begins with a '#'.
test_data = ( test_data = (
'<p><a href="#narrow/stream/test/topic/test.20topic/near/142"' '<p><a href="#narrow/stream/test/topic/test.20topic/near/142"'
+ 'title="#narrow/stream/test/topic/test.20topic/near/142">Conversation</a></p>' ' title="#narrow/stream/test/topic/test.20topic/near/142">Conversation</a></p>'
) )
actual_output = convert(test_data) actual_output = convert(test_data)
expected_output = ( expected_output = (
'<div><p><a href="http://example.com/#narrow/stream/test/topic/test.20topic/near/142" ' '<div><p><a href="http://example.com/#narrow/stream/test/topic/test.20topic/near/142"'
+ 'title="http://example.com/#narrow/stream/test/topic/test.20topic/near/142">Conversation</a></p></div>' ' title="http://example.com/#narrow/stream/test/topic/test.20topic/near/142">Conversation</a></p></div>'
) )
self.assertEqual(actual_output, expected_output) self.assertEqual(actual_output, expected_output)
# Scrub inline images. # Scrub inline images.
test_data = ( test_data = (
'<p>See this <a href="/user_uploads/{realm_id}/52/fG7GM9e3afz_qsiUcSce2tl_/avatar_103.jpeg" target="_blank" ' "<p>See this <a"
+ 'title="avatar_103.jpeg">avatar_103.jpeg</a>.</p>' ' href="/user_uploads/{realm_id}/52/fG7GM9e3afz_qsiUcSce2tl_/avatar_103.jpeg"'
+ '<div class="message_inline_image"><a href="/user_uploads/{realm_id}/52/fG7GM9e3afz_qsiUcSce2tl_/avatar_103.jpeg" ' ' target="_blank" title="avatar_103.jpeg">avatar_103.jpeg</a>.</p>'
+ 'target="_blank" title="avatar_103.jpeg"><img src="/user_uploads/{realm_id}/52/fG7GM9e3afz_qsiUcSce2tl_/avatar_103.jpeg"></a></div>' '<div class="message_inline_image"><a'
' href="/user_uploads/{realm_id}/52/fG7GM9e3afz_qsiUcSce2tl_/avatar_103.jpeg"'
' target="_blank" title="avatar_103.jpeg"><img'
' src="/user_uploads/{realm_id}/52/fG7GM9e3afz_qsiUcSce2tl_/avatar_103.jpeg"></a></div>'
) )
test_data = test_data.format(realm_id=zulip_realm.id) test_data = test_data.format(realm_id=zulip_realm.id)
actual_output = convert(test_data) actual_output = convert(test_data)
expected_output = ( expected_output = (
'<div><p>See this <a href="http://example.com/user_uploads/{realm_id}/52/fG7GM9e3afz_qsiUcSce2tl_/avatar_103.jpeg" target="_blank" ' "<div><p>See this <a"
+ 'title="avatar_103.jpeg">avatar_103.jpeg</a>.</p></div>' ' href="http://example.com/user_uploads/{realm_id}/52/fG7GM9e3afz_qsiUcSce2tl_/avatar_103.jpeg"'
' target="_blank" title="avatar_103.jpeg">avatar_103.jpeg</a>.</p></div>'
) )
expected_output = expected_output.format(realm_id=zulip_realm.id) expected_output = expected_output.format(realm_id=zulip_realm.id)
self.assertEqual(actual_output, expected_output) self.assertEqual(actual_output, expected_output)
@ -1493,16 +1497,17 @@ class TestMissedMessages(ZulipTestCase):
# A message containing only an inline image URL preview, we do # A message containing only an inline image URL preview, we do
# somewhat more extensive surgery. # somewhat more extensive surgery.
test_data = ( test_data = (
'<div class="message_inline_image"><a href="https://www.google.com/images/srpr/logo4w.png" ' '<div class="message_inline_image"><a'
+ 'target="_blank" title="https://www.google.com/images/srpr/logo4w.png">' ' href="https://www.google.com/images/srpr/logo4w.png"'
+ '<img data-src-fullsize="/thumbnail/https%3A//www.google.com/images/srpr/logo4w.png?size=0x0" ' ' target="_blank" title="https://www.google.com/images/srpr/logo4w.png">'
+ 'src="/thumbnail/https%3A//www.google.com/images/srpr/logo4w.png?size=0x100"></a></div>' '<img data-src-fullsize="/thumbnail/https%3A//www.google.com/images/srpr/logo4w.png?size=0x0"'
' src="/thumbnail/https%3A//www.google.com/images/srpr/logo4w.png?size=0x100"></a></div>'
) )
actual_output = convert(test_data) actual_output = convert(test_data)
expected_output = ( expected_output = (
'<div><p><a href="https://www.google.com/images/srpr/logo4w.png" ' '<div><p><a href="https://www.google.com/images/srpr/logo4w.png"'
+ 'target="_blank" title="https://www.google.com/images/srpr/logo4w.png">' ' target="_blank" title="https://www.google.com/images/srpr/logo4w.png">'
+ "https://www.google.com/images/srpr/logo4w.png</a></p></div>" "https://www.google.com/images/srpr/logo4w.png</a></p></div>"
) )
self.assertEqual(actual_output, expected_output) self.assertEqual(actual_output, expected_output)
@ -1548,15 +1553,17 @@ class TestMissedMessages(ZulipTestCase):
def test_fix_emoji(self) -> None: def test_fix_emoji(self) -> None:
# An emoji. # An emoji.
test_data = ( test_data = (
'<p>See <span aria-label="cloud with lightning and rain" class="emoji emoji-26c8" role="img" title="cloud with lightning and rain">' '<p>See <span aria-label="cloud with lightning and rain" class="emoji emoji-26c8"'
+ ":cloud_with_lightning_and_rain:</span>.</p>" ' role="img" title="cloud with lightning and'
' rain">:cloud_with_lightning_and_rain:</span>.</p>'
) )
fragment = lxml.html.fromstring(test_data) fragment = lxml.html.fromstring(test_data)
fix_emojis(fragment, "http://example.com", "google") fix_emojis(fragment, "http://example.com", "google")
actual_output = lxml.html.tostring(fragment, encoding="unicode") actual_output = lxml.html.tostring(fragment, encoding="unicode")
expected_output = ( expected_output = (
'<p>See <img alt=":cloud_with_lightning_and_rain:" src="http://example.com/static/generated/emoji/images-google-64/26c8.png" ' '<p>See <img alt=":cloud_with_lightning_and_rain:"'
+ 'title="cloud with lightning and rain" style="height: 20px;">.</p>' ' src="http://example.com/static/generated/emoji/images-google-64/26c8.png"'
' title="cloud with lightning and rain" style="height: 20px;">.</p>'
) )
self.assertEqual(actual_output, expected_output) self.assertEqual(actual_output, expected_output)

View File

@ -589,9 +589,13 @@ class PreviewTestCase(ZulipTestCase):
msg = Message.objects.select_related("sender").get(id=msg_id) msg = Message.objects.select_related("sender").get(id=msg_id)
with_preview = ( with_preview = (
'<p><a href="http://test.org/">http://test.org/</a></p>\n<div class="message_embed"><a class="message_embed_image" href="http://test.org/" style="background-image: url(' '<p><a href="http://test.org/">http://test.org/</a></p>\n'
+ "http\\:\\/\\/ia\\.media-imdb\\.com\\/images\\/rock\\)\\.jpg" '<div class="message_embed"><a class="message_embed_image" href="http://test.org/"'
+ ')"></a><div class="data-container"><div class="message_embed_title"><a href="http://test.org/" title="The Rock">The Rock</a></div><div class="message_embed_description">Description text</div></div></div>' ' style="background-image:'
' url(http\\:\\/\\/ia\\.media-imdb\\.com\\/images\\/rock\\)\\.jpg)"></a><div'
' class="data-container"><div class="message_embed_title"><a href="http://test.org/"'
' title="The Rock">The Rock</a></div><div class="message_embed_description">Description'
" text</div></div></div>"
) )
self.assertEqual( self.assertEqual(
with_preview, with_preview,

View File

@ -2894,13 +2894,15 @@ class MarkdownTest(ZulipTestCase):
def test_disabled_code_block_processor(self) -> None: def test_disabled_code_block_processor(self) -> None:
msg = ( msg = (
"Hello,\n\n" "Hello,\n\n"
+ " I am writing this message to test something. I am writing this message to test something." " I am writing this message to test something. I am writing this message to test"
" something."
) )
converted = markdown_convert_wrapper(msg) converted = markdown_convert_wrapper(msg)
expected_output = ( expected_output = (
"<p>Hello,</p>\n" "<p>Hello,</p>\n"
+ '<div class="codehilite"><pre><span></span><code>I am writing this message to test something. I am writing this message to test something.\n' '<div class="codehilite"><pre><span></span><code>I am writing this message to test'
+ "</code></pre></div>" " something. I am writing this message to test something.\n"
"</code></pre></div>"
) )
self.assertEqual(converted, expected_output) self.assertEqual(converted, expected_output)
@ -2911,7 +2913,8 @@ class MarkdownTest(ZulipTestCase):
rendering_result = markdown_convert(msg, message_realm=realm, email_gateway=True) rendering_result = markdown_convert(msg, message_realm=realm, email_gateway=True)
expected_output = ( expected_output = (
"<p>Hello,</p>\n" "<p>Hello,</p>\n"
+ "<p>I am writing this message to test something. I am writing this message to test something.</p>" "<p>I am writing this message to test something. I am writing this message to test"
" something.</p>"
) )
self.assertEqual(rendering_result.rendered_content, expected_output) self.assertEqual(rendering_result.rendered_content, expected_output)

View File

@ -2178,8 +2178,10 @@ class GetOldMessagesTest(ZulipTestCase):
self.assertEqual(meeting_message[MATCH_TOPIC], "meetings") self.assertEqual(meeting_message[MATCH_TOPIC], "meetings")
self.assertEqual( self.assertEqual(
meeting_message["match_content"], meeting_message["match_content"],
'<p>discuss <span class="highlight">lunch</span> after ' (
+ '<span class="highlight">lunch</span></p>', '<p>discuss <span class="highlight">lunch</span> after <span'
' class="highlight">lunch</span></p>'
),
) )
(lunch_message,) = (m for m in messages if m[TOPIC_NAME] == "lunch plans") (lunch_message,) = (m for m in messages if m[TOPIC_NAME] == "lunch plans")
@ -2224,7 +2226,7 @@ class GetOldMessagesTest(ZulipTestCase):
self.assertEqual(japanese_message[MATCH_TOPIC], '<span class="highlight">日本</span>') self.assertEqual(japanese_message[MATCH_TOPIC], '<span class="highlight">日本</span>')
self.assertEqual( self.assertEqual(
japanese_message["match_content"], japanese_message["match_content"],
'<p>昨日、<span class="highlight">日本</span>' + " のお菓子を送りました。</p>", '<p>昨日、<span class="highlight">日本</span> のお菓子を送りました。</p>',
) )
(english_message,) = (m for m in messages if m[TOPIC_NAME] == "english") (english_message,) = (m for m in messages if m[TOPIC_NAME] == "english")
@ -2372,7 +2374,7 @@ class GetOldMessagesTest(ZulipTestCase):
self.assertEqual(japanese_message[MATCH_TOPIC], '<span class="highlight">日本</span>語') self.assertEqual(japanese_message[MATCH_TOPIC], '<span class="highlight">日本</span>語')
self.assertEqual( self.assertEqual(
japanese_message["match_content"], japanese_message["match_content"],
'<p>昨日、<span class="highlight">日本</span>の' + "お菓子を送りました。</p>", '<p>昨日、<span class="highlight">日本</span>のお菓子を送りました。</p>',
) )
english_message = [m for m in messages if m[TOPIC_NAME] == "english"][0] english_message = [m for m in messages if m[TOPIC_NAME] == "english"][0]

View File

@ -123,8 +123,8 @@ class OpenGraphTest(ZulipTestCase):
"Logging out | Zulip help center", "Logging out | Zulip help center",
# Ideally we'd do something better here # Ideally we'd do something better here
[ [
"Your feedback helps us make Zulip better for everyone! Please contact us " "Your feedback helps us make Zulip better for everyone! Please contact us with"
+ "with questions, suggestions, and feature requests." " questions, suggestions, and feature requests."
], ],
["Click on the gear"], ["Click on the gear"],
) )

View File

@ -132,14 +132,19 @@ class TestBrowserAndOsUserAgentStrings(ZulipTestCase):
super().setUp() super().setUp()
self.user_agents = [ self.user_agents = [
( (
"mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) " (
+ "Chrome/54.0.2840.59 Safari/537.36", "mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)"
" Chrome/54.0.2840.59 Safari/537.36"
),
"Chrome", "Chrome",
"Linux", "Linux",
), ),
( (
"mozilla/5.0 (windows nt 6.1; win64; x64) applewebkit/537.36 (khtml, like gecko) " (
+ "chrome/56.0.2924.87 safari/537.36", "mozilla/5.0 (windows nt 6.1; win64; x64) "
" applewebkit/537.36 (khtml, like gecko)"
" chrome/56.0.2924.87 safari/537.36"
),
"Chrome", "Chrome",
"Windows", "Windows",
), ),
@ -159,36 +164,46 @@ class TestBrowserAndOsUserAgentStrings(ZulipTestCase):
"Android", "Android",
), ),
( (
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " (
"AppleWebKit/602.1.50 (KHTML, like Gecko) " "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X)"
"CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1", " AppleWebKit/602.1.50 (KHTML, like Gecko)"
" CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1"
),
"Chrome", "Chrome",
"iOS", "iOS",
), ),
( (
"Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) " (
+ "AppleWebKit/536.26 (KHTML, like Gecko) " "Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X)"
+ "Version/6.0 Mobile/10B329 Safari/8536.25", " AppleWebKit/536.26 (KHTML, like Gecko)"
" Version/6.0 Mobile/10B329 Safari/8536.25"
),
"Safari", "Safari",
"iOS", "iOS",
), ),
( (
"Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_4 like Mac OS X) " (
+ "AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B350", "Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_4 like Mac OS X)"
" AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B350"
),
None, None,
"iOS", "iOS",
), ),
( (
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) " (
+ "AppleWebKit/537.36 (KHTML, like Gecko) " "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6)"
+ "Chrome/56.0.2924.87 Safari/537.36", " AppleWebKit/537.36 (KHTML, like Gecko)"
" Chrome/56.0.2924.87 Safari/537.36"
),
"Chrome", "Chrome",
"macOS", "macOS",
), ),
( (
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) " (
+ "AppleWebKit/602.3.12 (KHTML, like Gecko) " "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6)"
+ "Version/10.0.2 Safari/602.3.12", " AppleWebKit/602.3.12 (KHTML, like Gecko)"
" Version/10.0.2 Safari/602.3.12"
),
"Safari", "Safari",
"macOS", "macOS",
), ),
@ -196,37 +211,46 @@ class TestBrowserAndOsUserAgentStrings(ZulipTestCase):
("ZulipMobile/1.0.12 (Android 7.1.1)", "Zulip", "Android"), ("ZulipMobile/1.0.12 (Android 7.1.1)", "Zulip", "Android"),
("ZulipMobile/0.7.1.1 (iOS 10.3.1)", "Zulip", "iOS"), ("ZulipMobile/0.7.1.1 (iOS 10.3.1)", "Zulip", "iOS"),
( (
"ZulipElectron/1.1.0-beta Mozilla/5.0 (Windows NT 10.0; Win64; x64) " (
+ "AppleWebKit/537.36 (KHTML, like Gecko) Zulip/1.1.0-beta " "ZulipElectron/1.1.0-beta Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
+ "Chrome/56.0.2924.87 Electron/1.6.8 Safari/537.36", " AppleWebKit/537.36 (KHTML, like Gecko) Zulip/1.1.0-beta"
" Chrome/56.0.2924.87 Electron/1.6.8 Safari/537.36"
),
"Zulip", "Zulip",
"Windows", "Windows",
), ),
( (
"Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, " (
"like Gecko) Ubuntu/11.10 Chromium/16.0.912.77 " "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko)"
"Chrome/16.0.912.77 Safari/535.7", " Ubuntu/11.10 Chromium/16.0.912.77 Chrome/16.0.912.77 Safari/535.7"
),
"Chromium", "Chromium",
"Linux", "Linux",
), ),
( (
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 " (
"(KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36 " "Mozilla/5.0 (Windows NT 6.1; WOW64)"
"OPR/15.0.1147.100", " AppleWebKit/537.36 (KHTML, like Gecko)"
" Chrome/28.0.1500.52 Safari/537.36 OPR/15.0.1147.100"
),
"Opera", "Opera",
"Windows", "Windows",
), ),
( (
"Mozilla/5.0 (Windows NT 10.0; <64-bit tags>) AppleWebKit/" (
"<WebKit Rev> (KHTML, like Gecko) Chrome/<Chrome Rev> Safari" "Mozilla/5.0 (Windows NT 10.0; <64-bit tags>)"
"/<WebKit Rev> Edge/<EdgeHTML Rev>." " AppleWebKit/<WebKit Rev> (KHTML, like Gecko)"
"<Windows Build>", " Chrome/<Chrome Rev> Safari/<WebKit Rev>"
" Edge/<EdgeHTML Rev>.<Windows Build>"
),
"Edge", "Edge",
"Windows", "Windows",
), ),
( (
"Mozilla/5.0 (X11; CrOS x86_64 10895.56.0) AppleWebKit/537.36 " (
"(KHTML, like Gecko) Chrome/69.0.3497.95 Safari/537.36", "Mozilla/5.0 (X11; CrOS x86_64 10895.56.0) AppleWebKit/537.36"
" (KHTML, like Gecko) Chrome/69.0.3497.95 Safari/537.36"
),
"Chrome", "Chrome",
"ChromeOS", "ChromeOS",
), ),

View File

@ -189,9 +189,10 @@ class ArchiveMessagesTestingBase(RetentionTestingBase):
self.subscribe(user_profile, "Denmark") self.subscribe(user_profile, "Denmark")
body = ( body = (
"Some files here ... [zulip.txt](http://{host}/user_uploads/{id}/31/4CBjtTLYZhk66pZrF8hnYGwc/zulip.txt)" "Some files here ..."
+ " http://{host}/user_uploads/{id}/31/4CBjtTLYZhk66pZrF8hnYGwc/temp_file.py.... Some more...." " [zulip.txt](http://{host}/user_uploads/{id}/31/4CBjtTLYZhk66pZrF8hnYGwc/zulip.txt)"
+ " http://{host}/user_uploads/{id}/31/4CBjtTLYZhk66pZrF8hnYGwc/abc.py" " http://{host}/user_uploads/{id}/31/4CBjtTLYZhk66pZrF8hnYGwc/temp_file.py.... Some"
" more.... http://{host}/user_uploads/{id}/31/4CBjtTLYZhk66pZrF8hnYGwc/abc.py"
).format(id=realm_id, host=host) ).format(id=realm_id, host=host)
expired_message_id = self.send_stream_message(user_profile, "Denmark", body) expired_message_id = self.send_stream_message(user_profile, "Denmark", body)

View File

@ -1348,9 +1348,10 @@ class InviteUserTest(InviteUserBase):
result = self.invite(invitee_emails, ["Denmark"]) result = self.invite(invitee_emails, ["Denmark"])
self.assert_json_error( self.assert_json_error(
result, result,
"Some of those addresses are already using Zulip," (
+ " so we didn't send them an invitation." "Some of those addresses are already using Zulip, so we didn't send them an"
+ " We did send invitations to everyone else!", " invitation. We did send invitations to everyone else!"
),
) )
def test_invite_mirror_dummy_user(self) -> None: def test_invite_mirror_dummy_user(self) -> None:

View File

@ -2082,7 +2082,7 @@ class StreamAdminTest(ZulipTestCase):
# Simulate that a stream by the same name has already been # Simulate that a stream by the same name has already been
# deactivated, just to exercise our renaming logic: # deactivated, just to exercise our renaming logic:
# Since we do not know the id of these simulated stream we prepend the name with a random hashed_stream_id # Since we do not know the id of these simulated stream we prepend the name with a random hashed_stream_id
ensure_stream(realm, "DB32B77" + "!DEACTIVATED:" + active_name, acting_user=None) ensure_stream(realm, "DB32B77!DEACTIVATED:" + active_name, acting_user=None)
events: List[Mapping[str, Any]] = [] events: List[Mapping[str, Any]] = []
with self.tornado_redirected_to_list(events, expected_num_events=1): with self.tornado_redirected_to_list(events, expected_num_events=1):

View File

@ -16,8 +16,8 @@ from .support_event import SUPPORT_EVENTS
DOCUMENT_TEMPLATE = "{user_name} {verb} the document [{title}]({url})" DOCUMENT_TEMPLATE = "{user_name} {verb} the document [{title}]({url})"
QUESTION_TEMPLATE = "{user_name} {verb} the question [{title}]({url})" QUESTION_TEMPLATE = "{user_name} {verb} the question [{title}]({url})"
QUESTIONS_ANSWER_TEMPLATE = ( QUESTIONS_ANSWER_TEMPLATE = (
"{user_name} {verb} the [answer]({answer_url}) " "{user_name} {verb} the [answer]({answer_url})"
+ "of the question [{question_title}]({question_url})" " of the question [{question_title}]({question_url})"
) )
COMMENT_TEMPLATE = ( COMMENT_TEMPLATE = (
"{user_name} {verb} the [comment]({answer_url}) of the task [{task_title}]({task_url})" "{user_name} {verb} the [comment]({answer_url}) of the task [{task_title}]({task_url})"

View File

@ -158,7 +158,7 @@ Billing method: send invoice"""
expected_topic = "cus_00000000000000" expected_topic = "cus_00000000000000"
expected_message = ( expected_message = (
"[Customer](https://dashboard.stripe.com/customers/cus_00000000000000) updated" "[Customer](https://dashboard.stripe.com/customers/cus_00000000000000) updated"
+ "\n* Account balance is now 100" "\n* Account balance is now 100"
) )
self.check_webhook( self.check_webhook(
"customer_updated__account_balance", "customer_updated__account_balance",

View File

@ -81,8 +81,9 @@ class TaigaHookTests(WebhookTestCase):
def test_taiga_userstory_changed_due_date(self) -> None: def test_taiga_userstory_changed_due_date(self) -> None:
message = ( message = (
"[Aditya Verma](https://tree.taiga.io/profile/orientor) changed due date of user story " "[Aditya Verma](https://tree.taiga.io/profile/orientor) changed due date of user story"
+ "[Nice Issue](https://tree.taiga.io/project/orientor-sd/us/54) from 2020-02-15 to 2020-02-22." " [Nice Issue](https://tree.taiga.io/project/orientor-sd/us/54) from 2020-02-15 to"
" 2020-02-22."
) )
self.check_webhook("userstory_changed_due_date", self.TOPIC, message) self.check_webhook("userstory_changed_due_date", self.TOPIC, message)
@ -145,7 +146,8 @@ class TaigaHookTests(WebhookTestCase):
def test_taiga_task_changed_due_date(self) -> None: def test_taiga_task_changed_due_date(self) -> None:
message = ( message = (
"[Aditya Verma](https://tree.taiga.io/profile/orientor) changed due date of task" "[Aditya Verma](https://tree.taiga.io/profile/orientor) changed due date of task"
+ " [nice task](https://tree.taiga.io/project/orientor-sd/task/56) from 2020-02-22 to 2020-02-15." " [nice task](https://tree.taiga.io/project/orientor-sd/task/56) from 2020-02-22 to"
" 2020-02-15."
) )
self.check_webhook("task_changed_due_date", self.TOPIC, message) self.check_webhook("task_changed_due_date", self.TOPIC, message)
@ -235,8 +237,9 @@ class TaigaHookTests(WebhookTestCase):
def test_taiga_issue_changed_due_date(self) -> None: def test_taiga_issue_changed_due_date(self) -> None:
message = ( message = (
"[Aditya Verma](https://tree.taiga.io/profile/orientor) changed due date of issue [Issues](https://tree.taiga.io/project/orientor-sd/issue/49) " "[Aditya Verma](https://tree.taiga.io/profile/orientor) changed due date of issue"
+ "from 2020-03-08 to 2020-02-22." " [Issues](https://tree.taiga.io/project/orientor-sd/issue/49) from 2020-03-08 to"
" 2020-02-22."
) )
self.check_webhook("issue_changed_due_date", self.TOPIC, message) self.check_webhook("issue_changed_due_date", self.TOPIC, message)
@ -302,8 +305,9 @@ class TaigaHookTests(WebhookTestCase):
def test_taiga_relateduserstory_created_link(self) -> None: def test_taiga_relateduserstory_created_link(self) -> None:
message = ( message = (
"[Aditya Verma](https://tree.taiga.io/profile/orientor) added a related user story [Nice Issue](https://tree.taiga.io/project/orientor-sd/us/54) " "[Aditya Verma](https://tree.taiga.io/profile/orientor) added a related user story"
+ "to the epic [ASAS](https://tree.taiga.io/project/orientor-sd/epic/42)." " [Nice Issue](https://tree.taiga.io/project/orientor-sd/us/54) to the epic"
" [ASAS](https://tree.taiga.io/project/orientor-sd/epic/42)."
) )
self.check_webhook("relateduserstory_created_link", self.TOPIC, message) self.check_webhook("relateduserstory_created_link", self.TOPIC, message)

View File

@ -59,12 +59,12 @@ templates = {
}, },
"relateduserstory": { "relateduserstory": {
"create": ( "create": (
"[{user}]({user_link}) added a related user story " "[{user}]({user_link}) added a related user story"
"{userstory_subject} to the epic {epic_subject}." " {userstory_subject} to the epic {epic_subject}."
), ),
"delete": ( "delete": (
"[{user}]({user_link}) removed a related user story " "[{user}]({user_link}) removed a related user story"
+ "{userstory_subject} from the epic {epic_subject}." " {userstory_subject} from the epic {epic_subject}."
), ),
}, },
"userstory": { "userstory": {

View File

@ -52,7 +52,7 @@ ACTIONS_TO_MESSAGE_MAPPER = {
SET_DESC: "set description for {card_url_template} to:\n~~~ quote\n{desc}\n~~~\n", SET_DESC: "set description for {card_url_template} to:\n~~~ quote\n{desc}\n~~~\n",
CHANGE_DESC: ( CHANGE_DESC: (
"changed description for {card_url_template} from\n" "changed description for {card_url_template} from\n"
+ "~~~ quote\n{old_desc}\n~~~\nto\n~~~ quote\n{desc}\n~~~\n" "~~~ quote\n{old_desc}\n~~~\nto\n~~~ quote\n{desc}\n~~~\n"
), ),
REMOVE_DESC: "removed description from {card_url_template}.", REMOVE_DESC: "removed description from {card_url_template}.",
ARCHIVE: "archived {card_url_template}.", ARCHIVE: "archived {card_url_template}.",

View File

@ -2299,9 +2299,9 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
] ]
if idps_without_limit_to_subdomains: if idps_without_limit_to_subdomains:
self.logger.error( self.logger.error(
"SAML_REQUIRE_LIMIT_TO_SUBDOMAINS is enabled and the following " "SAML_REQUIRE_LIMIT_TO_SUBDOMAINS is enabled and the following IdPs don't have"
+ "IdPs don't have limit_to_subdomains specified and will be ignored: " " limit_to_subdomains specified and will be ignored:"
+ f"{idps_without_limit_to_subdomains}" f" {idps_without_limit_to_subdomains}"
) )
for idp_name in idps_without_limit_to_subdomains: for idp_name in idps_without_limit_to_subdomains:
del settings.SOCIAL_AUTH_SAML_ENABLED_IDPS[idp_name] del settings.SOCIAL_AUTH_SAML_ENABLED_IDPS[idp_name]
@ -2437,8 +2437,8 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
return return
error_msg = ( error_msg = (
f"SAML user from IdP {idp.name} rejected due to missing entitlement " f"SAML user from IdP {idp.name} rejected due to missing entitlement for subdomain"
+ f"for subdomain '{subdomain}'. User entitlements: {entitlements}." f" '{subdomain}'. User entitlements: {entitlements}."
) )
raise AuthFailed(self, error_msg) raise AuthFailed(self, error_msg)
@ -2545,7 +2545,7 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
subdomain = self.choose_subdomain(relayed_params) subdomain = self.choose_subdomain(relayed_params)
if subdomain is None: if subdomain is None:
error_msg = ( error_msg = (
"/complete/saml/: Can't figure out subdomain for this %s. " + "relayed_params: %s" "/complete/saml/: Can't figure out subdomain for this %s. relayed_params: %s"
) )
self.logger.info(error_msg, saml_document.document_type(), relayed_params) self.logger.info(error_msg, saml_document.document_type(), relayed_params)
return None return None
@ -2560,8 +2560,8 @@ class SAMLAuthBackend(SocialAuthMixin, SAMLAuth):
idp_valid = self.validate_idp_for_subdomain(idp_name, subdomain) idp_valid = self.validate_idp_for_subdomain(idp_name, subdomain)
if not idp_valid: if not idp_valid:
error_msg = ( error_msg = (
"/complete/saml/: Authentication request with IdP %s but this provider is not " "/complete/saml/: Authentication request with IdP %s but this provider is not"
+ "enabled for this subdomain %s." " enabled for this subdomain %s."
) )
self.logger.info(error_msg, idp_name, subdomain) self.logger.info(error_msg, idp_name, subdomain)
return None return None