Mercurial > hg-stable
diff mercurial/mail.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | 2cc453284d5c |
children | 687b865b95ad |
line wrap: on
line diff
--- a/mercurial/mail.py Sat Oct 05 10:29:34 2019 -0400 +++ b/mercurial/mail.py Sun Oct 06 09:45:02 2019 -0400 @@ -31,11 +31,13 @@ stringutil, ) + class STARTTLS(smtplib.SMTP): '''Derived class to verify the peer certificate for STARTTLS. This class allows to pass any keyword arguments to SSL socket creation. ''' + def __init__(self, ui, host=None, **kwargs): smtplib.SMTP.__init__(self, **kwargs) self._ui = ui @@ -47,9 +49,13 @@ raise smtplib.SMTPException(msg) (resp, reply) = self.docmd("STARTTLS") if resp == 220: - self.sock = sslutil.wrapsocket(self.sock, keyfile, certfile, - ui=self._ui, - serverhostname=self._host) + self.sock = sslutil.wrapsocket( + self.sock, + keyfile, + certfile, + ui=self._ui, + serverhostname=self._host, + ) self.file = smtplib.SSLFakeFile(self.sock) self.helo_resp = None self.ehlo_resp = None @@ -57,13 +63,14 @@ self.does_esmtp = 0 return (resp, reply) + class SMTPS(smtplib.SMTP): '''Derived class to verify the peer certificate for SMTPS. This class allows to pass any keyword arguments to SSL socket creation. ''' - def __init__(self, ui, keyfile=None, certfile=None, host=None, - **kwargs): + + def __init__(self, ui, keyfile=None, certfile=None, host=None, **kwargs): self.keyfile = keyfile self.certfile = certfile smtplib.SMTP.__init__(self, **kwargs) @@ -75,22 +82,28 @@ if self.debuglevel > 0: self._ui.debug('connect: %r\n' % ((host, port),)) new_socket = socket.create_connection((host, port), timeout) - new_socket = sslutil.wrapsocket(new_socket, - self.keyfile, self.certfile, - ui=self._ui, - serverhostname=self._host) + new_socket = sslutil.wrapsocket( + new_socket, + self.keyfile, + self.certfile, + ui=self._ui, + serverhostname=self._host, + ) self.file = new_socket.makefile(r'rb') return new_socket + def _pyhastls(): """Returns true iff Python has TLS support, false otherwise.""" try: import ssl + getattr(ssl, 'HAS_TLS', False) return True except ImportError: return False + def _smtp(ui): '''build an smtp connection and return a function to send mail''' local_hostname = ui.config('smtp', 'local_hostname') @@ -115,8 +128,7 @@ else: defaultport = 25 mailport = util.getport(ui.config('smtp', 'port', defaultport)) - ui.note(_('sending mail: smtp host %s, port %d\n') % - (mailhost, mailport)) + ui.note(_('sending mail: smtp host %s, port %d\n') % (mailhost, mailport)) s.connect(host=mailhost, port=mailport) if starttls: ui.note(_('(using starttls)\n')) @@ -131,8 +143,7 @@ if username and not password: password = ui.getpass() if username and password: - ui.note(_('(authenticating to mail server as %s)\n') % - (username)) + ui.note(_('(authenticating to mail server as %s)\n') % username) try: s.login(username, password) except smtplib.SMTPException as inst: @@ -149,21 +160,31 @@ return send + def _sendmail(ui, sender, recipients, msg): '''send mail using sendmail.''' program = ui.config('email', 'method') stremail = lambda x: ( - procutil.quote(stringutil.email(encoding.strtolocal(x)))) - cmdline = '%s -f %s %s' % (program, stremail(sender), - ' '.join(map(stremail, recipients))) + procutil.quote(stringutil.email(encoding.strtolocal(x))) + ) + cmdline = '%s -f %s %s' % ( + program, + stremail(sender), + ' '.join(map(stremail, recipients)), + ) ui.note(_('sending mail: %s\n') % cmdline) fp = procutil.popen(cmdline, 'wb') fp.write(util.tonativeeol(msg)) ret = fp.close() if ret: - raise error.Abort('%s %s' % ( - os.path.basename(program.split(None, 1)[0]), - procutil.explainexit(ret))) + raise error.Abort( + '%s %s' + % ( + os.path.basename(program.split(None, 1)[0]), + procutil.explainexit(ret), + ) + ) + def _mbox(mbox, sender, recipients, msg): '''write mails to mbox''' @@ -171,12 +192,15 @@ # Should be time.asctime(), but Windows prints 2-characters day # of month instead of one. Make them print the same thing. date = time.strftime(r'%a %b %d %H:%M:%S %Y', time.localtime()) - fp.write('From %s %s\n' % (encoding.strtolocal(sender), - encoding.strtolocal(date))) + fp.write( + 'From %s %s\n' + % (encoding.strtolocal(sender), encoding.strtolocal(date)) + ) fp.write(msg) fp.write('\n\n') fp.close() + def connect(ui, mbox=None): '''make a mail connection. return a function to send mail. call as sendmail(sender, list-of-recipients, msg).''' @@ -187,21 +211,30 @@ return _smtp(ui) return lambda s, r, m: _sendmail(ui, s, r, m) + def sendmail(ui, sender, recipients, msg, mbox=None): send = connect(ui, mbox=mbox) return send(sender, recipients, msg) + def validateconfig(ui): '''determine if we have enough config data to try sending email.''' method = ui.config('email', 'method') if method == 'smtp': if not ui.config('smtp', 'host'): - raise error.Abort(_('smtp specified as email transport, ' - 'but no smtp host configured')) + raise error.Abort( + _( + 'smtp specified as email transport, ' + 'but no smtp host configured' + ) + ) else: if not procutil.findexe(method): - raise error.Abort(_('%r specified as email transport, ' - 'but not in PATH') % method) + raise error.Abort( + _('%r specified as email transport, ' 'but not in PATH') + % method + ) + def codec2iana(cs): '''''' @@ -212,6 +245,7 @@ return "iso-" + cs[3:] return cs + def mimetextpatch(s, subtype='plain', display=False): '''Return MIME message suitable for a patch. Charset will be detected by first trying to decode as us-ascii, then utf-8, @@ -231,6 +265,7 @@ return mimetextqp(s, subtype, "iso-8859-1") + def mimetextqp(body, subtype, charset): '''Return MIME message. Quoted-printable transfer encoding will be used if necessary. @@ -255,16 +290,21 @@ return msg + def _charsets(ui): '''Obtains charsets to send mail parts not containing patches.''' charsets = [cs.lower() for cs in ui.configlist('email', 'charsets')] - fallbacks = [encoding.fallbackencoding.lower(), - encoding.encoding.lower(), 'utf-8'] - for cs in fallbacks: # find unique charsets while keeping order + fallbacks = [ + encoding.fallbackencoding.lower(), + encoding.encoding.lower(), + 'utf-8', + ] + for cs in fallbacks: # find unique charsets while keeping order if cs not in charsets: charsets.append(cs) return [cs for cs in charsets if not cs.endswith('ascii')] + def _encode(ui, s, charsets): '''Returns (converted) string, charset tuple. Finds out best charset by cycling through sendcharsets in descending @@ -307,6 +347,7 @@ # if ascii, or all conversion attempts fail, send (broken) ascii return s, 'us-ascii' + def headencode(ui, s, charsets=None, display=False): '''Returns RFC-2047 compliant header from given string.''' if not display: @@ -315,6 +356,7 @@ return str(email.header.Header(s, cs)) return s + def _addressencode(ui, name, addr, charsets=None): assert isinstance(addr, bytes) name = headencode(ui, name, charsets) @@ -332,7 +374,9 @@ except UnicodeDecodeError: raise error.Abort(_('invalid local address: %s') % addr) return pycompat.bytesurl( - email.utils.formataddr((name, encoding.strfromlocal(addr)))) + email.utils.formataddr((name, encoding.strfromlocal(addr))) + ) + def addressencode(ui, address, charsets=None, display=False): '''Turns address into RFC-2047 compliant header.''' @@ -341,23 +385,26 @@ name, addr = email.utils.parseaddr(encoding.strfromlocal(address)) return _addressencode(ui, name, encoding.strtolocal(addr), charsets) + def addrlistencode(ui, addrs, charsets=None, display=False): '''Turns a list of addresses into a list of RFC-2047 compliant headers. A single element of input list may contain multiple addresses, but output always has one address per item''' for a in addrs: - assert isinstance(a, bytes), (r'%r unexpectedly not a bytestr' % a) + assert isinstance(a, bytes), r'%r unexpectedly not a bytestr' % a if display: return [a.strip() for a in addrs if a.strip()] result = [] for name, addr in email.utils.getaddresses( - [encoding.strfromlocal(a) for a in addrs]): + [encoding.strfromlocal(a) for a in addrs] + ): if name or addr: r = _addressencode(ui, name, encoding.strtolocal(addr), charsets) result.append(r) return result + def mimeencode(ui, s, charsets=None, display=False): '''creates mime text object, encodes it if needed, and sets charset and transfer-encoding accordingly.''' @@ -366,23 +413,30 @@ s, cs = _encode(ui, s, charsets) return mimetextqp(s, 'plain', cs) + if pycompat.ispy3: + def parse(fp): ep = email.parser.Parser() # disable the "universal newlines" mode, which isn't binary safe. # I have no idea if ascii/surrogateescape is correct, but that's # what the standard Python email parser does. - fp = io.TextIOWrapper(fp, encoding=r'ascii', - errors=r'surrogateescape', newline=chr(10)) + fp = io.TextIOWrapper( + fp, encoding=r'ascii', errors=r'surrogateescape', newline=chr(10) + ) try: return ep.parse(fp) finally: fp.detach() + + else: + def parse(fp): ep = email.parser.Parser() return ep.parse(fp) + def headdecode(s): '''Decodes RFC-2047 header''' uparts = []