mirror of https://github.com/zulip/zulip.git
python: Pre-fix a few spots for better Black formatting.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
c67ea05423
commit
f91d287447
|
@ -124,8 +124,10 @@ _properties = {
|
|||
Confirmation.INVITATION: ConfirmationType('check_prereg_key_and_redirect',
|
||||
validity_in_days=settings.INVITATION_LINK_VALIDITY_DAYS),
|
||||
Confirmation.EMAIL_CHANGE: ConfirmationType('zerver.views.user_settings.confirm_email_change'),
|
||||
Confirmation.UNSUBSCRIBE: ConfirmationType('zerver.views.unsubscribe.email_unsubscribe',
|
||||
validity_in_days=1000000), # should never expire
|
||||
Confirmation.UNSUBSCRIBE: ConfirmationType(
|
||||
'zerver.views.unsubscribe.email_unsubscribe',
|
||||
validity_in_days=1000000, # should never expire
|
||||
),
|
||||
Confirmation.MULTIUSE_INVITE: ConfirmationType(
|
||||
'zerver.views.registration.accounts_home_from_multiuse_invite',
|
||||
validity_in_days=settings.INVITATION_LINK_VALIDITY_DAYS),
|
||||
|
|
|
@ -47,10 +47,11 @@ output = subprocess.check_output(['/usr/sbin/rabbitmqctl', 'list_consumers'],
|
|||
consumers: Dict[str, int] = defaultdict(int)
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
|
||||
queues = set(normal_queues).union({
|
||||
queues = {
|
||||
*normal_queues,
|
||||
# These queues may not be present if settings.TORNADO_PROCESSES > 1
|
||||
'notify_tornado',
|
||||
})
|
||||
}
|
||||
|
||||
for queue_name in queues:
|
||||
queue_name = queue_name.strip()
|
||||
|
|
|
@ -97,9 +97,9 @@ def restore_backup(tarball_file: IO[bytes]) -> None:
|
|||
run(
|
||||
[
|
||||
os.path.join(
|
||||
settings.DEPLOY_ROOT, "scripts", "setup", "terminate-psql-sessions",
|
||||
settings.DEPLOY_ROOT, "scripts", "setup", "terminate-psql-sessions"
|
||||
),
|
||||
db["NAME"],
|
||||
db["NAME"]
|
||||
],
|
||||
env=postgres_env,
|
||||
)
|
||||
|
@ -136,8 +136,8 @@ def restore_backup(tarball_file: IO[bytes]) -> None:
|
|||
run(
|
||||
[
|
||||
os.path.join(settings.DEPLOY_ROOT, "scripts", "zulip-puppet-apply"),
|
||||
"-f",
|
||||
],
|
||||
"-f"
|
||||
]
|
||||
)
|
||||
|
||||
# Now, restore the the database backup using pg_restore. This
|
||||
|
|
|
@ -28,7 +28,7 @@ EXCLUDED_URLS = [
|
|||
'https://www.udemy.com/course/the-complete-react-native-and-redux-course/',
|
||||
]
|
||||
|
||||
VNU_IGNORE = re.compile(r'|'.join([
|
||||
VNU_IGNORE = [
|
||||
# Real errors that should be fixed.
|
||||
r'Duplicate ID “[^”]*”\.',
|
||||
r'The first occurrence of ID “[^”]*” was here\.',
|
||||
|
@ -39,7 +39,8 @@ VNU_IGNORE = re.compile(r'|'.join([
|
|||
|
||||
# Warnings that are probably less important.
|
||||
r'The “type” attribute is unnecessary for JavaScript resources\.',
|
||||
]))
|
||||
]
|
||||
VNU_IGNORE_REGEX = re.compile(r'|'.join(VNU_IGNORE))
|
||||
|
||||
|
||||
class BaseDocumentationSpider(scrapy.Spider):
|
||||
|
@ -91,7 +92,7 @@ class BaseDocumentationSpider(scrapy.Spider):
|
|||
def callback(response: Response) -> None:
|
||||
vnu_out = json.loads(response.text)
|
||||
for message in vnu_out['messages']:
|
||||
if not VNU_IGNORE.fullmatch(message['message']):
|
||||
if not VNU_IGNORE_REGEX.fullmatch(message['message']):
|
||||
self.logger.error(
|
||||
'"%s":%d.%d-%d.%d: %s: %s',
|
||||
url,
|
||||
|
|
|
@ -174,15 +174,15 @@ SPLIT_BOUNDARY = '?.!' # Used to split string into sentences.
|
|||
SPLIT_BOUNDARY_REGEX = re.compile(fr'[{SPLIT_BOUNDARY}]')
|
||||
|
||||
# Regexes which check capitalization in sentences.
|
||||
DISALLOWED_REGEXES = [re.compile(regex) for regex in [
|
||||
DISALLOWED = [
|
||||
r'^[a-z](?!\})', # Checks if the sentence starts with a lower case character.
|
||||
r'^[A-Z][a-z]+[\sa-z0-9]+[A-Z]', # Checks if an upper case character exists
|
||||
# after a lower case character when the first character is in upper case.
|
||||
]]
|
||||
]
|
||||
DISALLOWED_REGEX = re.compile(r"|".join(DISALLOWED))
|
||||
|
||||
BANNED_WORDS = {
|
||||
'realm': ('The term realm should not appear in user-facing strings. '
|
||||
'Use organization instead.'),
|
||||
'realm': 'The term realm should not appear in user-facing strings. Use organization instead.',
|
||||
}
|
||||
|
||||
def get_safe_phrase(phrase: str) -> str:
|
||||
|
@ -232,18 +232,7 @@ def get_safe_text(text: str) -> str:
|
|||
|
||||
def is_capitalized(safe_text: str) -> bool:
|
||||
sentences = SPLIT_BOUNDARY_REGEX.split(safe_text)
|
||||
sentences = [sentence.strip()
|
||||
for sentence in sentences if sentence.strip()]
|
||||
|
||||
if not sentences:
|
||||
return False
|
||||
|
||||
for sentence in sentences:
|
||||
for regex in DISALLOWED_REGEXES:
|
||||
if regex.search(sentence):
|
||||
return False
|
||||
|
||||
return True
|
||||
return not any(DISALLOWED_REGEX.search(sentence.strip()) for sentence in sentences)
|
||||
|
||||
def check_banned_words(text: str) -> List[str]:
|
||||
lower_cased_text = text.lower()
|
||||
|
|
|
@ -72,7 +72,7 @@ WORD_SET = {
|
|||
'uses', 'using', 'used',
|
||||
}
|
||||
|
||||
imperative_forms = sorted([
|
||||
imperative_forms = [
|
||||
'add', 'allow', 'amend', 'bump', 'calculate', 'change', 'clean', 'commit',
|
||||
'correct', 'create', 'darken', 'disable', 'display', 'document', 'dry',
|
||||
'end', 'enforce', 'enqueue', 'extract', 'finish', 'fix', 'format', 'guard',
|
||||
|
@ -81,7 +81,8 @@ imperative_forms = sorted([
|
|||
'refactor', 'remove', 'rename', 'reorder', 'replace', 'require', 'restore',
|
||||
'send', 'separate', 'set', 'show', 'simplify', 'skip', 'sort', 'speed',
|
||||
'start', 'support', 'take', 'test', 'truncate', 'update', 'use',
|
||||
])
|
||||
]
|
||||
imperative_forms.sort()
|
||||
|
||||
|
||||
def head_binary_search(key: Text, words: List[str]) -> str:
|
||||
|
|
|
@ -22,7 +22,7 @@ import responses
|
|||
from django.conf import settings
|
||||
from django.test.utils import get_runner
|
||||
|
||||
target_fully_covered = {path for target in [
|
||||
target_fully_covered = [
|
||||
'analytics/lib/*.py',
|
||||
'analytics/models.py',
|
||||
'analytics/tests/*.py',
|
||||
|
@ -51,9 +51,9 @@ target_fully_covered = {path for target in [
|
|||
# 'zerver/webhooks/*/*.py',
|
||||
# 'zerver/webhooks/*/*/*.py',
|
||||
'zerver/worker/*.py',
|
||||
] for path in glob.glob(target)}
|
||||
]
|
||||
|
||||
not_yet_fully_covered = {path for target in [
|
||||
not_yet_fully_covered = [
|
||||
# Analytics fixtures library is used to generate test fixtures;
|
||||
# isn't properly accounted for in test coverage analysis since it
|
||||
# runs before tests.
|
||||
|
@ -136,9 +136,12 @@ not_yet_fully_covered = {path for target in [
|
|||
'zerver/webhooks/teamcity/view.py',
|
||||
'zerver/webhooks/travis/view.py',
|
||||
'zerver/webhooks/zapier/view.py',
|
||||
] for path in glob.glob(target)}
|
||||
]
|
||||
|
||||
enforce_fully_covered = sorted(target_fully_covered - not_yet_fully_covered)
|
||||
enforce_fully_covered = sorted(
|
||||
{path for target in target_fully_covered for path in glob.glob(target)}
|
||||
- {path for target in not_yet_fully_covered for path in glob.glob(target)}
|
||||
)
|
||||
|
||||
FAILED_TEST_PATH = 'var/last_test_failure.json'
|
||||
|
||||
|
|
|
@ -102,10 +102,9 @@ class IsCapitalizedTestCase(TestCase):
|
|||
|
||||
string = ""
|
||||
capitalized = is_capitalized(string)
|
||||
self.assertFalse(capitalized)
|
||||
self.assertTrue(capitalized)
|
||||
|
||||
string = ("Please re-enter your password to confirm your identity."
|
||||
" (Forgotten it?)")
|
||||
string = "Please re-enter your password to confirm your identity. (Forgotten it?)"
|
||||
capitalized = is_capitalized(string)
|
||||
self.assertTrue(capitalized)
|
||||
|
||||
|
|
|
@ -300,7 +300,8 @@ def build_recipient(type_id: int, recipient_id: int, type: int) -> ZerverFieldsT
|
|||
recipient = Recipient(
|
||||
type_id=type_id, # stream id
|
||||
id=recipient_id,
|
||||
type=type)
|
||||
type=type,
|
||||
)
|
||||
recipient_dict = model_to_dict(recipient)
|
||||
return recipient_dict
|
||||
|
||||
|
|
|
@ -1534,7 +1534,8 @@ def do_send_messages(messages_maybe_none: Sequence[Optional[MutableMapping[str,
|
|||
if message['stream'] is None:
|
||||
stream_id = message['message'].recipient.type_id
|
||||
message['stream'] = Stream.objects.select_related().get(id=stream_id)
|
||||
assert message['stream'] is not None # assert needed because stubs for django are missing
|
||||
# assert needed because stubs for django are missing
|
||||
assert message['stream'] is not None
|
||||
realm_id = message['stream'].realm_id
|
||||
|
||||
# Deliver events to the real-time push system, as well as
|
||||
|
@ -1592,7 +1593,9 @@ def do_send_messages(messages_maybe_none: Sequence[Optional[MutableMapping[str,
|
|||
# notify new_message request if it's a public stream,
|
||||
# ensuring that in the tornado server, non-public stream
|
||||
# messages are only associated to their subscribed users.
|
||||
assert message['stream'] is not None # assert needed because stubs for django are missing
|
||||
|
||||
# assert needed because stubs for django are missing
|
||||
assert message['stream'] is not None
|
||||
if message['stream'].is_public():
|
||||
event['realm_id'] = message['stream'].realm_id
|
||||
event['stream_name'] = message['stream'].name
|
||||
|
|
|
@ -25,8 +25,7 @@ ALL_HOTSPOTS: Dict[str, Dict[str, str]] = {
|
|||
},
|
||||
'intro_gear': {
|
||||
'title': _('Settings'),
|
||||
'description': _('Go to Settings to configure your '
|
||||
'notifications and display settings.'),
|
||||
'description': _('Go to Settings to configure your notifications and display settings.'),
|
||||
},
|
||||
'intro_compose': {
|
||||
'title': _('Compose'),
|
||||
|
|
|
@ -405,8 +405,7 @@ class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
|
|||
def format_spoiler(self, header: str, text: str) -> str:
|
||||
output = []
|
||||
header_div_open_html = '<div class="spoiler-block"><div class="spoiler-header">'
|
||||
end_header_start_content_html = '</div><div class="spoiler-content"' \
|
||||
' aria-hidden="true">'
|
||||
end_header_start_content_html = '</div><div class="spoiler-content" aria-hidden="true">'
|
||||
footer_html = '</div></div>'
|
||||
|
||||
output.append(self.placeholder(header_div_open_html))
|
||||
|
|
|
@ -17,7 +17,7 @@ def is_disposable_domain(domain: str) -> bool:
|
|||
return False
|
||||
return domain.lower() in DISPOSABLE_DOMAINS
|
||||
|
||||
ZULIP_RESERVED_SUBDOMAINS = frozenset([
|
||||
ZULIP_RESERVED_SUBDOMAINS = {
|
||||
# zulip terms
|
||||
'stream', 'channel', 'topic', 'thread', 'installation', 'organization', 'realm',
|
||||
'team', 'subdomain', 'activity', 'octopus', 'acme', 'push',
|
||||
|
@ -40,12 +40,12 @@ ZULIP_RESERVED_SUBDOMAINS = frozenset([
|
|||
# Things that sound like security
|
||||
'auth', 'authentication', 'security',
|
||||
# tech blogs
|
||||
'engineering', 'infrastructure', 'tooling', 'tools', 'javascript', 'python'])
|
||||
'engineering', 'infrastructure', 'tooling', 'tools', 'javascript', 'python'}
|
||||
|
||||
# Most of this list was curated from the following sources:
|
||||
# http://wiki.dwscoalition.org/notes/List_of_reserved_subdomains (license: CC-BY-SA 3.0)
|
||||
# https://stackoverflow.com/questions/11868191/which-saas-subdomains-to-block (license: CC-BY-SA 2.5)
|
||||
GENERIC_RESERVED_SUBDOMAINS = frozenset([
|
||||
GENERIC_RESERVED_SUBDOMAINS = {
|
||||
'about', 'abuse', 'account', 'ad', 'admanager', 'admin', 'admindashboard',
|
||||
'administrator', 'adsense', 'adword', 'affiliate', 'alpha', 'anonymous',
|
||||
'api', 'assets', 'audio', 'badges', 'beta', 'billing', 'biz', 'blog',
|
||||
|
@ -77,12 +77,12 @@ GENERIC_RESERVED_SUBDOMAINS = frozenset([
|
|||
'testers', 'ticket', 'tool', 'tos', 'trac', 'translate', 'update',
|
||||
'upgrade', 'uploads', 'use', 'user', 'username', 'validation', 'videos',
|
||||
'volunteer', 'web', 'webdisk', 'webmail', 'webmaster', 'whm', 'whois',
|
||||
'wiki', 'www', 'www0', 'www8', 'www9', 'xml', 'xmpp', 'xoxo'])
|
||||
'wiki', 'www', 'www0', 'www8', 'www9', 'xml', 'xmpp', 'xoxo'}
|
||||
|
||||
DISPOSABLE_DOMAINS = frozenset(blacklist)
|
||||
DISPOSABLE_DOMAINS = set(blacklist)
|
||||
|
||||
WHITELISTED_EMAIL_DOMAINS = frozenset([
|
||||
WHITELISTED_EMAIL_DOMAINS = {
|
||||
# Controlled by https://www.abine.com; more legitimate than most
|
||||
# disposable domains
|
||||
'opayq.com', 'abinemail.com', 'blurmail.net', 'maskmemail.com',
|
||||
])
|
||||
}
|
||||
|
|
|
@ -94,18 +94,19 @@ class Database:
|
|||
# what the database is as runtime.
|
||||
# Also we export ZULIP_DB_NAME which is ignored by dev platform but
|
||||
# recognised by test platform and used to migrate correct db.
|
||||
env_prelude = [
|
||||
manage_py = [
|
||||
'env',
|
||||
'DJANGO_SETTINGS_MODULE=' + self.settings,
|
||||
'ZULIP_DB_NAME=' + self.database_name,
|
||||
'./manage.py',
|
||||
]
|
||||
|
||||
run([
|
||||
*env_prelude, './manage.py', 'migrate', '--no-input',
|
||||
*manage_py, 'migrate', '--no-input'
|
||||
])
|
||||
|
||||
run([
|
||||
*env_prelude, './manage.py', 'get_migration_status', '--output='+self.migration_status_file,
|
||||
*manage_py, 'get_migration_status', '--output='+self.migration_status_file
|
||||
])
|
||||
|
||||
def what_to_do_with_migrations(self) -> str:
|
||||
|
|
|
@ -79,9 +79,9 @@ class TextTestResult(runner.TextTestResult):
|
|||
|
||||
def addSkip(self, test: TestCase, reason: str) -> None:
|
||||
TestResult.addSkip(self, test, reason)
|
||||
self.stream.writeln("** Skipping {}: {}".format( # type: ignore[attr-defined] # https://github.com/python/typeshed/issues/3139
|
||||
test.id(),
|
||||
reason))
|
||||
self.stream.writeln( # type: ignore[attr-defined] # https://github.com/python/typeshed/issues/3139
|
||||
"** Skipping {}: {}".format(test.id(), reason)
|
||||
)
|
||||
self.stream.flush()
|
||||
|
||||
class RemoteTestResult(django_runner.RemoteTestResult):
|
||||
|
|
|
@ -182,11 +182,11 @@ def resize_emoji(image_data: bytes, size: int=DEFAULT_EMOJI_SIZE) -> bytes:
|
|||
# results in resized gifs being broken. To work around this we
|
||||
# only resize under certain conditions to minimize the chance of
|
||||
# creating ugly gifs.
|
||||
should_resize = any((
|
||||
im.size[0] != im.size[1], # not square
|
||||
im.size[0] > MAX_EMOJI_GIF_SIZE, # dimensions too large
|
||||
len(image_data) > MAX_EMOJI_GIF_FILE_SIZE_BYTES, # filesize too large
|
||||
))
|
||||
should_resize = (
|
||||
im.size[0] != im.size[1] # not square
|
||||
or im.size[0] > MAX_EMOJI_GIF_SIZE # dimensions too large
|
||||
or len(image_data) > MAX_EMOJI_GIF_FILE_SIZE_BYTES # filesize too large
|
||||
)
|
||||
return resize_gif(im, size) if should_resize else image_data
|
||||
else:
|
||||
im = exif_rotate(im)
|
||||
|
|
|
@ -153,7 +153,6 @@ def query_chunker(queries: List[Any],
|
|||
q = q.order_by('id')
|
||||
min_id = -1
|
||||
while True:
|
||||
assert db_chunk_size is not None # Hint for mypy, but also workaround for mypy bug #3442.
|
||||
rows = list(q.filter(id__gt=min_id)[0:db_chunk_size])
|
||||
if len(rows) == 0:
|
||||
break
|
||||
|
|
|
@ -53,7 +53,8 @@ def get_imap_messages() -> Generator[EmailMessage, None, None]:
|
|||
assert isinstance(msg_data[0], tuple)
|
||||
msg_as_bytes = msg_data[0][1]
|
||||
message = email.message_from_bytes(msg_as_bytes, policy=email.policy.default)
|
||||
assert isinstance(message, EmailMessage) # https://github.com/python/typeshed/issues/2417
|
||||
# https://github.com/python/typeshed/issues/2417
|
||||
assert isinstance(message, EmailMessage)
|
||||
yield message
|
||||
mbox.store(message_id, '+FLAGS', '\\Deleted')
|
||||
mbox.expunge()
|
||||
|
|
|
@ -94,7 +94,8 @@ Example:
|
|||
else:
|
||||
with open(fixture_path, "rb") as fp:
|
||||
message = email.message_from_binary_file(fp, policy=email.policy.default)
|
||||
assert isinstance(message, EmailMessage) # https://github.com/python/typeshed/issues/2417
|
||||
# https://github.com/python/typeshed/issues/2417
|
||||
assert isinstance(message, EmailMessage)
|
||||
return message
|
||||
|
||||
def _prepare_message(self, message: EmailMessage, realm: Realm, stream_name: str) -> None:
|
||||
|
|
|
@ -383,7 +383,8 @@ class RateLimitMiddleware(MiddlewareMixin):
|
|||
def process_exception(self, request: HttpRequest,
|
||||
exception: Exception) -> Optional[HttpResponse]:
|
||||
if isinstance(exception, RateLimited):
|
||||
secs_to_freedom = float(str(exception)) # secs_to_freedom is passed to RateLimited when raising
|
||||
# secs_to_freedom is passed to RateLimited when raising
|
||||
secs_to_freedom = float(str(exception))
|
||||
resp = json_error(
|
||||
_("API usage exceeded rate limit"),
|
||||
data={'retry-after': secs_to_freedom},
|
||||
|
|
|
@ -1409,7 +1409,7 @@ def filter_to_valid_prereg_users(query: QuerySet) -> QuerySet:
|
|||
|
||||
class MultiuseInvite(models.Model):
|
||||
id: int = models.AutoField(auto_created=True, primary_key=True, verbose_name='ID')
|
||||
referred_by: UserProfile = models.ForeignKey(UserProfile, on_delete=CASCADE) # Optional[UserProfile]
|
||||
referred_by: UserProfile = models.ForeignKey(UserProfile, on_delete=CASCADE)
|
||||
streams: Manager = models.ManyToManyField('Stream')
|
||||
realm: Realm = models.ForeignKey(Realm, on_delete=CASCADE)
|
||||
invited_as: int = models.PositiveSmallIntegerField(default=PreregistrationUser.INVITE_AS['MEMBER'])
|
||||
|
@ -2599,7 +2599,8 @@ class UserPresence(models.Model):
|
|||
@staticmethod
|
||||
def status_from_string(status: str) -> Optional[int]:
|
||||
if status == 'active':
|
||||
status_val: Optional[int] = UserPresence.ACTIVE # See https://github.com/python/mypy/issues/2611
|
||||
# See https://github.com/python/mypy/issues/2611
|
||||
status_val: Optional[int] = UserPresence.ACTIVE
|
||||
elif status == 'idle':
|
||||
status_val = UserPresence.IDLE
|
||||
else:
|
||||
|
|
|
@ -576,7 +576,8 @@ class RateLimitAuthenticationTests(ZulipTestCase):
|
|||
with mock.patch('time.time', return_value=start_time + 11.0):
|
||||
self.assertIsNone(attempt_authentication(username, wrong_password))
|
||||
|
||||
self.assertEqual(attempt_authentication(username, correct_password), expected_user_profile) # Correct password
|
||||
# Correct password
|
||||
self.assertEqual(attempt_authentication(username, correct_password), expected_user_profile)
|
||||
# A correct login attempt should reset the rate limits for this user profile,
|
||||
# so the next two attempts shouldn't get limited:
|
||||
self.assertIsNone(attempt_authentication(username, wrong_password))
|
||||
|
@ -1704,7 +1705,7 @@ class SAMLAuthBackendTest(SocialAuthBase):
|
|||
relay_state = orjson.dumps(dict(
|
||||
state_token=SAMLAuthBackend.put_data_in_redis({"subdomain": "zulip"}),
|
||||
)).decode()
|
||||
post_params = {"RelayState": relay_state, 'SAMLResponse': 'dGVzdA=='} # base64 encoded 'test'
|
||||
post_params = {"RelayState": relay_state, 'SAMLResponse': base64.b64encode(b"test").decode()}
|
||||
result = self.client_post('/complete/saml/', post_params)
|
||||
self.assertEqual(result.status_code, 302)
|
||||
self.assertIn('login', result.url)
|
||||
|
@ -1756,7 +1757,7 @@ class SAMLAuthBackendTest(SocialAuthBase):
|
|||
relay_state = orjson.dumps(dict(
|
||||
state_token=SAMLAuthBackend.put_data_in_redis({"subdomain": "zulip"}),
|
||||
)).decode()
|
||||
post_params = {"RelayState": relay_state, 'SAMLResponse': 'dGVzdA=='}
|
||||
post_params = {"RelayState": relay_state, 'SAMLResponse': base64.b64encode(b"test").decode()}
|
||||
result = self.client_post('/complete/saml/', post_params)
|
||||
self.assertEqual(result.status_code, 302)
|
||||
self.assertIn('login', result.url)
|
||||
|
@ -4626,7 +4627,8 @@ class TestZulipLDAPUserPopulator(ZulipLDAPTestCase):
|
|||
do_deactivate_user(othello)
|
||||
mock_logger = mock.MagicMock()
|
||||
result = sync_user_from_ldap(othello, mock_logger)
|
||||
self.assertEqual(mock_logger.method_calls, []) # In this case the logger shouldn't be used.
|
||||
# In this case the logger shouldn't be used.
|
||||
self.assertEqual(mock_logger.method_calls, [])
|
||||
self.assertFalse(result)
|
||||
|
||||
def test_update_user_avatar(self) -> None:
|
||||
|
|
|
@ -1290,7 +1290,8 @@ class TestContentTypeUnspecifiedCharset(ZulipTestCase):
|
|||
message_as_string = message_as_string.replace("Content-Type: text/plain; charset=\"us-ascii\"",
|
||||
"Content-Type: text/plain")
|
||||
incoming_message = message_from_string(message_as_string, policy=email.policy.default)
|
||||
assert isinstance(incoming_message, EmailMessage) # https://github.com/python/typeshed/issues/2417
|
||||
# https://github.com/python/typeshed/issues/2417
|
||||
assert isinstance(incoming_message, EmailMessage)
|
||||
|
||||
user_profile = self.example_user('hamlet')
|
||||
self.login_user(user_profile)
|
||||
|
|
|
@ -285,7 +285,8 @@ class TestArchiveMessagesGeneral(ArchiveMessagesTestingBase):
|
|||
# Insert an exception near the end of the archiving process of a chunk:
|
||||
with mock.patch("zerver.lib.retention.delete_messages", side_effect=Exception):
|
||||
with self.assertRaises(Exception):
|
||||
archive_messages(chunk_size=1000) # Specify large chunk_size to ensure things happen in a single batch
|
||||
# Specify large chunk_size to ensure things happen in a single batch
|
||||
archive_messages(chunk_size=1000)
|
||||
|
||||
# Archiving code has been executed, but because we got an exception, things should have been rolled back:
|
||||
self._verify_archive_data([], [])
|
||||
|
@ -373,7 +374,8 @@ class TestArchiveMessagesGeneral(ArchiveMessagesTestingBase):
|
|||
restore_all_data_from_archive()
|
||||
# Attachments should have been restored:
|
||||
self.assertEqual(Attachment.objects.count(), 3)
|
||||
self.assertEqual(ArchivedAttachment.objects.count(), 3) # Archived data doesn't get deleted by restoring.
|
||||
# Archived data doesn't get deleted by restoring.
|
||||
self.assertEqual(ArchivedAttachment.objects.count(), 3)
|
||||
self.assertEqual(
|
||||
list(Attachment.objects.distinct('messages__id').order_by('messages__id').values_list(
|
||||
'messages__id', flat=True)),
|
||||
|
|
|
@ -64,7 +64,8 @@ class SlackMessageConversion(ZulipTestCase):
|
|||
{"id": "U09TYF5Sk",
|
||||
"name": "Jane",
|
||||
"is_mirror_dummy": False,
|
||||
"deleted": True}] # Deleted users don't have 'real_name' key in Slack
|
||||
"deleted": True, # Deleted users don't have 'real_name' key in Slack
|
||||
}]
|
||||
channel_map = {'general': ('C5Z73A7RA', 137)}
|
||||
message = 'Hi <@U08RGD1RD|john>: How are you? <#C5Z73A7RA|general>'
|
||||
text, mentioned_users, has_link = convert_to_zulip_markdown(message, users, channel_map, slack_user_map)
|
||||
|
|
|
@ -3392,7 +3392,8 @@ class SubscriptionAPITest(ZulipTestCase):
|
|||
self.assert_json_success(result)
|
||||
json = result.json()
|
||||
for key, val in json_dict.items():
|
||||
self.assertEqual(sorted(val), sorted(json[key])) # we don't care about the order of the items
|
||||
# we don't care about the order of the items
|
||||
self.assertEqual(sorted(val), sorted(json[key]))
|
||||
user = get_user(email, realm)
|
||||
new_streams = self.get_streams(user)
|
||||
self.assertEqual(sorted(new_streams), sorted(new_subs))
|
||||
|
@ -3425,7 +3426,8 @@ class SubscriptionAPITest(ZulipTestCase):
|
|||
"""
|
||||
random_streams = self.make_random_stream_names(self.streams)
|
||||
self.assertNotEqual(len(random_streams), 0) # necessary for full test coverage
|
||||
streams_to_remove = random_streams[:1] # pick only one fake stream, to make checking the error message easy
|
||||
# pick only one fake stream, to make checking the error message easy
|
||||
streams_to_remove = random_streams[:1]
|
||||
result = self.client_delete("/json/users/me/subscriptions",
|
||||
{"subscriptions": orjson.dumps(streams_to_remove).decode()})
|
||||
self.assert_json_error(result, f"Stream(s) ({random_streams[0]}) do not exist")
|
||||
|
|
|
@ -256,7 +256,8 @@ class EventQueue:
|
|||
|
||||
self.queue: Deque[Dict[str, Any]] = deque()
|
||||
self.next_event_id: int = 0
|
||||
self.newest_pruned_id: Optional[int] = -1 # will only be None for migration from old versions
|
||||
# will only be None for migration from old versions
|
||||
self.newest_pruned_id: Optional[int] = -1
|
||||
self.id: str = id
|
||||
self.virtual_events: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
|
|
|
@ -558,7 +558,8 @@ def log_into_subdomain(request: HttpRequest, token: str) -> HttpResponse:
|
|||
call login_or_register_remote_user, passing all the authentication
|
||||
result data that has been stored in redis, associated with this token.
|
||||
"""
|
||||
if not has_api_key_format(token): # The tokens are intended to have the same format as API keys.
|
||||
# The tokens are intended to have the same format as API keys.
|
||||
if not has_api_key_format(token):
|
||||
logging.warning("log_into_subdomain: Malformed token given: %s", token)
|
||||
return HttpResponse(status=400)
|
||||
|
||||
|
|
|
@ -208,11 +208,14 @@ def join_bigbluebutton(request: HttpRequest, meeting_id: str = REQ(validator=che
|
|||
if payload.find("returncode").text != "SUCCESS":
|
||||
return json_error(_("Big Blue Button server returned an unexpected error."))
|
||||
|
||||
join_params = urlencode({ # type: ignore[type-var] # https://github.com/python/typeshed/issues/4234
|
||||
"meetingID": meeting_id,
|
||||
"password": password,
|
||||
"fullName": request.user.full_name
|
||||
}, quote_via=quote)
|
||||
join_params = urlencode( # type: ignore[type-var] # https://github.com/python/typeshed/issues/4234
|
||||
{
|
||||
"meetingID": meeting_id,
|
||||
"password": password,
|
||||
"fullName": request.user.full_name,
|
||||
},
|
||||
quote_via=quote,
|
||||
)
|
||||
|
||||
checksum = hashlib.sha1(("join" + join_params + settings.BIG_BLUE_BUTTON_SECRET).encode()).hexdigest()
|
||||
redirect_url_base = add_query_to_redirect_url(settings.BIG_BLUE_BUTTON_URL + "api/join", join_params)
|
||||
|
|
|
@ -71,7 +71,7 @@ def repo_comment_handler(payload: Dict[str, Any], action: str) -> List[Dict[str,
|
|||
repo_name = payload["repository"]["name"]
|
||||
subject = BITBUCKET_TOPIC_TEMPLATE.format(repository_name=repo_name)
|
||||
sha = payload["commit"]
|
||||
commit_url = payload["repository"]["links"]["self"][0]["href"][:-6] # remove the "browse" at the end
|
||||
commit_url = payload["repository"]["links"]["self"][0]["href"][: -len("browse")]
|
||||
commit_url += f"commits/{sha}"
|
||||
message = payload["comment"]["text"]
|
||||
if action == "deleted their comment":
|
||||
|
|
|
@ -238,7 +238,8 @@ class GitlabHookTests(WebhookTestCase):
|
|||
def test_note_merge_request_event_message_without_merge_request_title(self) -> None:
|
||||
expected_topic = "my-awesome-project / MR #1"
|
||||
expected_message = "Tomasz Kolek [commented](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/1#note_14171860) on [MR #1](https://gitlab.com/tomaszkolek0/my-awesome-project/merge_requests/1):\n\n~~~ quote\nNice merge request!\n~~~"
|
||||
self.url = self.build_webhook_url(use_merge_request_title="false") # To keep things as valid JSON.
|
||||
# To keep things as valid JSON.
|
||||
self.url = self.build_webhook_url(use_merge_request_title="false")
|
||||
self.check_webhook("note_hook__merge_request_note", expected_topic, expected_message)
|
||||
|
||||
def test_note_merge_request_with_custom_topic_in_url(self) -> None:
|
||||
|
|
|
@ -1045,7 +1045,8 @@ class ZulipRemoteUserBackend(RemoteUserBackend, ExternalAuthMethod):
|
|||
auth_backend_name = "RemoteUser"
|
||||
name = "remoteuser"
|
||||
display_icon = None
|
||||
sort_order = 9000 # If configured, this backend should have its button near the top of the list.
|
||||
# If configured, this backend should have its button near the top of the list.
|
||||
sort_order = 9000
|
||||
|
||||
create_unknown_user = False
|
||||
|
||||
|
@ -1199,7 +1200,8 @@ def social_associate_user_helper(backend: BaseAuth, return_data: Dict[str, Any],
|
|||
# Some authentications methods like Apple and SAML send
|
||||
# first name and last name as separate attributes. In that case
|
||||
# we construct the full name from them.
|
||||
return_data["full_name"] = f"{first_name or ''} {last_name or ''}".strip() # strip removes the unnecessary ' '
|
||||
# strip removes the unnecessary ' '
|
||||
return_data["full_name"] = f"{first_name or ''} {last_name or ''}".strip()
|
||||
|
||||
return user_profile
|
||||
|
||||
|
|
|
@ -469,19 +469,24 @@ TWITTER_ACCESS_TOKEN_SECRET = get_secret("twitter_access_token_secret")
|
|||
# These are the bots that Zulip sends automated messages as.
|
||||
INTERNAL_BOTS = [{'var_name': 'NOTIFICATION_BOT',
|
||||
'email_template': 'notification-bot@%s',
|
||||
'name': 'Notification Bot'},
|
||||
'name': 'Notification Bot',
|
||||
},
|
||||
{'var_name': 'EMAIL_GATEWAY_BOT',
|
||||
'email_template': 'emailgateway@%s',
|
||||
'name': 'Email Gateway'},
|
||||
'name': 'Email Gateway',
|
||||
},
|
||||
{'var_name': 'NAGIOS_SEND_BOT',
|
||||
'email_template': 'nagios-send-bot@%s',
|
||||
'name': 'Nagios Send Bot'},
|
||||
'name': 'Nagios Send Bot',
|
||||
},
|
||||
{'var_name': 'NAGIOS_RECEIVE_BOT',
|
||||
'email_template': 'nagios-receive-bot@%s',
|
||||
'name': 'Nagios Receive Bot'},
|
||||
'name': 'Nagios Receive Bot',
|
||||
},
|
||||
{'var_name': 'WELCOME_BOT',
|
||||
'email_template': 'welcome-bot@%s',
|
||||
'name': 'Welcome Bot'}]
|
||||
'name': 'Welcome Bot',
|
||||
}]
|
||||
|
||||
# Bots that are created for each realm like the reminder-bot goes here.
|
||||
REALM_INTERNAL_BOTS: List[Dict[str, str]] = []
|
||||
|
@ -490,17 +495,20 @@ REALM_INTERNAL_BOTS: List[Dict[str, str]] = []
|
|||
DISABLED_REALM_INTERNAL_BOTS = [
|
||||
{'var_name': 'REMINDER_BOT',
|
||||
'email_template': 'reminder-bot@%s',
|
||||
'name': 'Reminder Bot'},
|
||||
'name': 'Reminder Bot',
|
||||
},
|
||||
]
|
||||
|
||||
if PRODUCTION:
|
||||
INTERNAL_BOTS += [
|
||||
{'var_name': 'NAGIOS_STAGING_SEND_BOT',
|
||||
'email_template': 'nagios-staging-send-bot@%s',
|
||||
'name': 'Nagios Staging Send Bot'},
|
||||
'name': 'Nagios Staging Send Bot',
|
||||
},
|
||||
{'var_name': 'NAGIOS_STAGING_RECEIVE_BOT',
|
||||
'email_template': 'nagios-staging-receive-bot@%s',
|
||||
'name': 'Nagios Staging Receive Bot'},
|
||||
'name': 'Nagios Staging Receive Bot',
|
||||
},
|
||||
]
|
||||
|
||||
INTERNAL_BOT_DOMAIN = "zulip.com"
|
||||
|
|
Loading…
Reference in New Issue