aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--build/lib/libbe/storage/util/config.py128
-rwxr-xr-xinterfaces/email/interactive/be-handle-mail335
-rw-r--r--interfaces/email/interactive/send_pgp_mime.py32
-rw-r--r--interfaces/web/web.py6
-rw-r--r--libbe/bugdir.py18
-rw-r--r--libbe/command/base.py48
-rw-r--r--libbe/command/comment.py8
-rw-r--r--libbe/command/commit.py8
-rw-r--r--libbe/command/depend.py14
-rw-r--r--libbe/command/diff.py8
-rw-r--r--libbe/command/due.py2
-rw-r--r--libbe/command/help.py2
-rw-r--r--libbe/command/html.py22
-rw-r--r--libbe/command/import_xml.py20
-rw-r--r--libbe/command/list.py6
-rw-r--r--libbe/command/merge.py2
-rw-r--r--libbe/command/new.py10
-rw-r--r--libbe/command/serve_commands.py2
-rw-r--r--libbe/command/set.py6
-rw-r--r--libbe/command/show.py2
-rw-r--r--libbe/command/subscribe.py14
-rw-r--r--libbe/command/tag.py4
-rw-r--r--libbe/command/target.py16
-rw-r--r--libbe/command/util.py18
-rw-r--r--libbe/diff.py14
-rw-r--r--libbe/storage/base.py9
-rw-r--r--libbe/storage/util/config.py4
-rw-r--r--libbe/storage/util/properties.py193
-rw-r--r--libbe/storage/util/settings_object.py40
-rw-r--r--libbe/storage/util/upgrade.py2
-rw-r--r--libbe/storage/vcs/base.py18
-rw-r--r--libbe/storage/vcs/bzr.py8
-rw-r--r--libbe/storage/vcs/darcs.py8
-rw-r--r--libbe/storage/vcs/git.py6
-rw-r--r--libbe/storage/vcs/hg.py6
-rw-r--r--libbe/storage/vcs/monotone.py10
-rw-r--r--libbe/ui/command_line.py14
-rw-r--r--libbe/ui/util/editor.py4
-rw-r--r--libbe/ui/util/user.py8
-rw-r--r--libbe/util/encoding.py10
-rw-r--r--libbe/util/id.py16
-rw-r--r--libbe/util/subproc.py8
-rw-r--r--libbe/util/wsgi.py8
-rwxr-xr-xmisc/xml/be-mail-to-xml99
-rwxr-xr-xmisc/xml/be-xml-to-mbox123
-rw-r--r--test.py2
m---------update-copyright0
48 files changed, 823 insertions, 519 deletions
diff --git a/.gitignore b/.gitignore
index 63a767f..0ec3bae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ doc/libbe/
.be/id-cache
libbe/_version.py
*.egg-info
+.idea/*
diff --git a/build/lib/libbe/storage/util/config.py b/build/lib/libbe/storage/util/config.py
new file mode 100644
index 0000000..34e17f4
--- /dev/null
+++ b/build/lib/libbe/storage/util/config.py
@@ -0,0 +1,128 @@
+# Copyright (C) 2005-2012 Aaron Bentley <abentley@panoramicfeedback.com>
+# Chris Ball <cjb@laptop.org>
+# Gianluca Montecchi <gian@grys.it>
+# W. Trevor King <wking@tremily.us>
+#
+# This file is part of Bugs Everywhere.
+#
+# Bugs Everywhere is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 2 of the License, or (at your option) any
+# later version.
+#
+# Bugs Everywhere is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Bugs Everywhere. If not, see <http://www.gnu.org/licenses/>.
+
+"""Create, save, and load the per-user config file at :py:func:`path`.
+"""
+
+import configparser
+import codecs
+import io
+import os
+import os.path
+
+import libbe
+import libbe.util.encoding
+if libbe.TESTING == True:
+ import doctest
+
+
+default_encoding = libbe.util.encoding.get_text_file_encoding()
+"""Default filesystem encoding.
+
+Initialized with :py:func:`libbe.util.encoding.get_text_file_encoding`.
+"""
+
+def path():
+ """Return the path to the per-user config file.
+
+ Defaults to :file:`~/.config/bugs-everywhere`, but you can
+ override the directory with ``XDG_CONFIG_HOME`` from the `XDG Base
+ Directory Specification`_. You can also override the entire path
+ by setting the ``BE_CONFIG_PATH`` environment variable.
+
+ .. _XDG Base Directory Specification:
+ http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ """
+ default_dir = os.path.join('~', '.config')
+ dirname = os.path.expanduser(
+ os.environ.get('XDG_CONFIG_HOME', default_dir))
+ default = os.path.join(dirname, 'bugs-everywhere')
+ return os.path.expanduser(os.environ.get('BE_CONFIG_PATH', default))
+
+def set_val(name, value, section="DEFAULT", encoding=None):
+ """Set a value in the per-user config file.
+
+ Parameters
+ ----------
+ name : str
+ The name of the value to set.
+ value : str or None
+ The new value to set (or None to delete the value).
+ section : str
+ The section to store the name/value in.
+ encoding : str
+ The config file's encoding, defaults to :py:data:`default_encoding`.
+ """
+ if encoding is None:
+ encoding = default_encoding
+ config = configparser.ConfigParser()
+ if os.path.exists(path()) == False: # touch file or config
+ open(path(), 'w').close() # read chokes on missing file
+ with io.open(path(), 'r', encoding) as f:
+ config.read_file(f, path())
+ if value is not None:
+ config.set(section, name, value)
+ else:
+ config.remove_option(section, name)
+ f = codecs.open(path(), 'w', encoding)
+ config.write(f)
+ f.close()
+
+def get_val(name, section="DEFAULT", default=None, encoding=None):
+ """Get a value from the per-user config file
+
+ Parameters
+ ----------
+ name : str
+ The name of the value to set.
+ section : str
+ The section to store the name/value in.
+ default :
+ The value to return if `name` is not set.
+ encoding : str
+ The config file's encoding, defaults to :py:data:`default_encoding`.
+
+ Examples
+ --------
+
+ >>> get_val("junk") is None
+ True
+ >>> set_val("junk", "random")
+ >>> get_val("junk")
+ u'random'
+ >>> set_val("junk", None)
+ >>> get_val("junk") is None
+ True
+ """
+ if os.path.exists(path()):
+ if encoding is None:
+ encoding = default_encoding
+ config = configparser.ConfigParser()
+ with io.open(path(), 'r', encoding) as f:
+ config.read_file(f, path())
+ try:
+ return config.get(section, name)
+ except configparser.NoOptionError:
+ return default
+ else:
+ return default
+
+if libbe.TESTING == True:
+ suite = doctest.DocTestSuite()
diff --git a/interfaces/email/interactive/be-handle-mail b/interfaces/email/interactive/be-handle-mail
index c5b87b1..d2805d5 100755
--- a/interfaces/email/interactive/be-handle-mail
+++ b/interfaces/email/interactive/be-handle-mail
@@ -50,9 +50,8 @@ executed, with the email's post-tag subject as the commit message.
"""
import codecs
-import StringIO as StringIO
+import doctest
import email
-from email.mime.multipart import MIMEMultipart
import email.utils
import os
import os.path
@@ -62,15 +61,15 @@ import sys
import time
import traceback
import types
-import doctest
import unittest
+from email.mime.multipart import MIMEMultipart
-import libbe.bugdir
import libbe.bug
-import libbe.comment
-import libbe.diff
+import libbe.bugdir
import libbe.command
import libbe.command.subscribe as subscribe
+import libbe.comment
+import libbe.diff
import libbe.storage
import libbe.ui.command_line
import libbe.util.encoding
@@ -105,12 +104,14 @@ ALLOWED_COMMANDS = [u'assign', u'comment', u'commit', u'depend', u'diff',
AUTOCOMMIT = True
ENCODING = u'utf-8'
-libbe.util.encoding.ENCODING = ENCODING # force default encoding
+libbe.util.encoding.ENCODING = ENCODING # force default encoding
+
-class InvalidEmail (ValueError):
+class InvalidEmail(ValueError):
def __init__(self, msg, message):
ValueError.__init__(self, message)
self.msg = msg
+
def response(self):
header = self.msg.response_header
body = [u'Error processing email:\n',
@@ -122,58 +123,70 @@ class InvalidEmail (ValueError):
response.attach(self.msg.msg)
ret = send_pgp_mime.attach_root(header, response)
return ret
+
def response_body(self):
- err_text = [unicode(self)]
+ err_text = [str(self)]
return u'\n'.join(err_text)
-class InvalidSubject (InvalidEmail):
+
+class InvalidSubject(InvalidEmail):
def __init__(self, msg, message=None):
- if message == None:
+ if message is None:
message = u'Invalid subject'
InvalidEmail.__init__(self, msg, message)
+
def response_body(self):
- err_text = u'\n'.join([unicode(self), u'',
+ err_text = u'\n'.join([str(self), u'',
u'full subject was:',
self.msg.subject()])
return err_text
-class InvalidPseudoHeader (InvalidEmail):
+
+class InvalidPseudoHeader(InvalidEmail):
def response_body(self):
err_text = [u'Invalid pseudo-header:\n',
- unicode(self)]
+ str(self)]
return u'\n'.join(err_text)
-class InvalidCommand (InvalidEmail):
+
+class InvalidCommand(InvalidEmail):
def __init__(self, msg, command, message=None):
bigmessage = u'Invalid execution command "%s"' % command
- if message != None:
+ if message is not None:
bigmessage += u'\n%s' % message
InvalidEmail.__init__(self, msg, bigmessage)
self.command = command
-class InvalidOption (InvalidCommand):
+
+class InvalidOption(InvalidCommand):
def __init__(self, msg, option, message=None):
- bigmessage = u'Invalid option "%s"' % (option)
- if message != None:
+ bigmessage = u'Invalid option "%s"' % option
+ info = ""
+ command = ""
+ if message is not None:
bigmessage += u'\n%s' % message
InvalidCommand.__init__(self, msg, info, command, bigmessage)
self.option = option
-class NotificationFailed (Exception):
+
+class NotificationFailed(Exception):
def __init__(self, msg):
bigmessage = 'Notification failed: %s' % msg
Exception.__init__(self, bigmessage)
self.short_msg = msg
-class ID (object):
+
+class ID(object):
"""
Sometimes you want to reference the output of a command that
hasn't been executed yet. ID is there for situations like
> a = Command(msg, "new", ["create a bug"])
> b = Command(msg, "comment", [ID(a), "and comment on it"])
"""
+
def __init__(self, command):
self.command = command
+
def extract_id(self):
if hasattr(self, 'cached_id'):
return self._cached_id
@@ -181,17 +194,19 @@ class ID (object):
if self.command.command.name == u'new':
regexp = re.compile(u'Created bug with ID (.*)')
else:
- raise NotImplementedError, self.command.command
+ raise NotImplementedError(self.command.command)
match = regexp.match(self.command.stdout)
assert len(match.groups()) == 1, str(match.groups())
self._cached_id = match.group(1)
return self._cached_id
+
def __str__(self):
if self.command.ret != 0:
return '<id for %s>' % repr(self.command)
return '<id %s>' % self.extract_id()
-class Command (object):
+
+class Command(object):
"""
A libbe.command.Command handler.
@@ -203,54 +218,60 @@ class Command (object):
args: list of arguments to pass to the command
stdin: if non-null, a string to pipe into the command's stdin
"""
+
def __init__(self, msg, command, args=None, stdin=None):
self.msg = msg
- if args == None:
+ if args is None:
self.args = []
else:
self.args = args
self.command = libbe.command.get_command_class(command_name=command)()
- self.command._setup_io = lambda i_enc,o_enc : None
+ self.command._setup_io = lambda i_enc, o_enc: None
self.ret = None
self.stdin = stdin
self.stdout = None
+
def __str__(self):
return '<command: %s %s>' % (self.command, ' '.join([str(s) for s in self.args]))
+
def normalize_args(self):
"""
Expand any ID placeholders in self.args.
"""
- for i,arg in enumerate(self.args):
+ for i, arg in enumerate(self.args):
if isinstance(arg, ID):
self.args[i] = arg.extract_id()
+
def run(self):
"""
Attempt to execute the command whose info is given in the dictionary
info. Returns the exit code, stdout, and stderr produced by the
command.
"""
- if self.command.name in [None, u'']: # don't accept blank commands
+ if self.command.name in [None, u'']: # don't accept blank commands
raise InvalidCommand(self.msg, self, 'Blank')
elif self.command.name not in ALLOWED_COMMANDS:
raise InvalidCommand(self.msg, self, 'Not allowed')
- assert self.ret == None, u'running %s twice!' % unicode(self)
+ assert self.ret is None, u'running %s twice!' % str(self)
self.normalize_args()
UI.io.set_stdin(self.stdin)
self.ret = libbe.ui.command_line.dispatch(UI, self.command, self.args)
self.stdout = UI.io.get_stdout()
return (self.ret, self.stdout)
+
def response_msg(self):
- if self.ret == None: self.ret = -1
+ if self.ret is None: self.ret = -1
response_body = [u'Results of running: (exit code %d)' % self.ret,
- u' %s %s' % (self.command.name,u' '.join(self.args))]
- if self.stdout != None and len(self.stdout) > 0:
+ u' %s %s' % (self.command.name, u' '.join(self.args))]
+ if self.stdout is not None and len(self.stdout) > 0:
response_body.extend([u'', u'output:', u'', self.stdout])
- response_body.append(u'') # trailing endline
+ response_body.append(u'') # trailing endline
response_generator = \
send_pgp_mime.PGPMimeMessageFactory(u'\n'.join(response_body))
return response_generator.plain()
-class DiffTree (libbe.diff.DiffTree):
+
+class DiffTree(libbe.diff.DiffTree):
"""
In order to avoid tons of tiny MIMEText attachments, bug-level
nodes set .add_child_text=True (in .join()), which is propogated
@@ -275,66 +296,80 @@ class DiffTree (libbe.diff.DiffTree):
bugdir/bugs/mod/a/comments/rem
bugdir/bugs/mod/a/comments/mod
"""
+
def report_or_none(self):
report = self.report()
- if report == None:
+ if report is None:
return None
payload = report.get_payload()
- if payload == None or len(payload) == 0:
+ if payload is None or len(payload) == 0:
return None
return report
+
def report_string(self):
report = self.report_or_none()
- if report == None:
+ if report is None:
return 'No changes'
else:
return send_pgp_mime.flatten(report, to_unicode=True)
+
def make_root(self):
return MIMEMultipart()
+
def join(self, root, parent, data_part):
if hasattr(parent, 'attach_child_text'):
self.attach_child_text = True
- if data_part != None:
+ if data_part is not None:
send_pgp_mime.append_text(parent.data_mime_part, u'\n\n%s' % (data_part))
self.data_mime_part = parent.data_mime_part
else:
self.data_mime_part = None
- if data_part != None:
+ if data_part is not None:
self.data_mime_part = send_pgp_mime.encodedMIMEText(data_part)
- if parent != None and parent.name in [u'new', u'rem', u'mod']:
+ if parent is not None and parent.name in [u'new', u'rem', u'mod']:
self.attach_child_text = True
- if data_part == None: # make blank data_mime_part for children's appends
+ if data_part is None: # make blank data_mime_part for children's appends
self.data_mime_part = send_pgp_mime.encodedMIMEText(u'')
- if self.data_mime_part != None:
+ if self.data_mime_part is not None:
self.data_mime_part[u'Content-Description'] = self.name
root.attach(self.data_mime_part)
+
def data_part(self, depth, indent=False):
return libbe.diff.DiffTree.data_part(self, depth, indent=indent)
-class Diff (libbe.diff.Diff):
- def bug_add_string(self, bug):
+
+class Diff(libbe.diff.Diff):
+ @staticmethod
+ def bug_add_string(bug):
return bug.string(show_comments=True)
- def _comment_summary_string(self, comment):
+
+ @staticmethod
+ def _comment_summary_string(comment):
return comment.string()
+
def comment_add_string(self, comment):
return self._comment_summary_string(comment)
+
def comment_rem_string(self, comment):
return self._comment_summary_string(comment)
-class Message (object):
+
+class Message(object):
def __init__(self, email_text=None, disable_parsing=False):
if disable_parsing == False:
self.text = email_text
- p=email.Parser.Parser()
- self.msg=p.parsestr(self.text)
- if LOGFILE != None:
+ p = email.Parser.Parser()
+ self.msg = p.parsestr(self.text)
+ if LOGFILE is not None:
LOGFILE.write(u'handling %s\n' % self.author_addr())
LOGFILE.write(u'\n%s\n\n' % self.text)
- self.confirm = True # enable/disable confirmation email
+ self.confirm = True # enable/disable confirmation email
+
def _yes_no(self, boolean):
if boolean == True:
return 'yes'
return 'no'
+
def author_tuple(self):
"""
Extract and normalize the sender's email address. Returns a
@@ -344,36 +379,44 @@ class Message (object):
self._author_tuple_cache = \
send_pgp_mime.source_email(self.msg, return_realname=True)
return self._author_tuple_cache
+
def author_addr(self):
return email.utils.formataddr(self.author_tuple())
+
def author_name(self):
return self.author_tuple()[0]
+
def author_email(self):
return self.author_tuple()[1]
+
def default_msg_attribute_access(self, attr_name, default=None):
if attr_name in self.msg:
return self.msg[attr_name]
return default
+
def message_id(self, default=None):
return self.default_msg_attribute_access('message-id', default=default)
+
def subject(self):
if 'subject' not in self.msg:
raise InvalidSubject(self, u'Email must contain a subject')
return self.msg['subject']
+
def _split_subject(self):
"""
Returns (tag, subject), with missing values replaced by None.
"""
if hasattr(self, '_split_subject_cache'):
return self._split_subject_cache
- args = self.subject().split(u']',1)
+ args = self.subject().split(u']', 1)
if len(args) < 1:
self._split_subject_cache = (None, None)
elif len(args) < 2:
- self._split_subject_cache = (args[0]+u']', None)
+ self._split_subject_cache = (args[0] + u']', None)
else:
- self._split_subject_cache = (args[0]+u']', args[1].strip())
+ self._split_subject_cache = (args[0] + u']', args[1].strip())
return self._split_subject_cache
+
def _subject_tag_type(self):
"""
Parse subject tag, return (type, value), where type is one of
@@ -381,7 +424,7 @@ class Message (object):
in the case of "comment", in which case it's the bug
ID/shortname.
"""
- tag,subject = self._split_subject()
+ tag, subject = self._split_subject()
type = None
value = None
if tag == SUBJECT_TAG_NEW:
@@ -394,21 +437,23 @@ class Message (object):
type = u'comment'
value = match.group(1)
return (type, value)
+
def validate_subject(self):
"""
Validate the subject line.
"""
- tag,subject = self._split_subject()
+ tag, subject = self._split_subject()
if not tag.startswith(SUBJECT_TAG_START):
raise InvalidSubject(
self, u'Subject must start with "%s"' % SUBJECT_TAG_START)
- tag_type,value = self._subject_tag_type()
- if tag_type == None:
+ tag_type, value = self._subject_tag_type()
+ if tag_type is None:
raise InvalidSubject(self, u'Invalid tag "%s"' % tag)
elif tag_type == u'new' and len(subject) == 0:
raise InvalidSubject(self, u'Cannot create a bug with blank title')
elif tag_type == u'comment' and len(value) == 0:
raise InvalidSubject(self, u'Must specify a bug ID to comment')
+
def _get_bodies_and_mime_types(self):
"""
Traverse the email message returning (body, mime_type) for
@@ -418,11 +463,12 @@ class Message (object):
for part in self.msg.walk():
if part.is_multipart():
continue
- body,mime_type=(part.get_payload(decode=True),part.get_content_type())
+ body, mime_type = (part.get_payload(decode=True), part.get_content_type())
charset = part.get_content_charset(msg_charset).lower()
if mime_type.startswith('text/'):
- body = unicode(body, charset) # convert text types to unicode
+ body = str(body, charset) # convert text types to unicode
yield (body, mime_type)
+
def _parse_body_pseudoheaders(self, body, required, optional,
dictionary=None):
"""
@@ -432,17 +478,17 @@ class Message (object):
like, you can initialize the dictionary with some defaults
and pass your initialized dict in as dictionary.
"""
- if dictionary == None:
+ if dictionary is None:
dictionary = {}
body_lines = body.splitlines()
- all = required+optional
- for i,line in enumerate(body_lines):
+ all = required + optional
+ for i, line in enumerate(body_lines):
line = line.strip()
if len(line) == 0:
break
if ':' not in line:
- raise InvalidPseudoheader(self, line)
- key,value = line.split(':', 1)
+ raise InvalidPseudoHeader(self, line)
+ key, value = line.split(':', 1)
value = value.strip()
if key not in all:
raise InvalidPseudoHeader(self, key)
@@ -460,13 +506,15 @@ class Message (object):
% u', '.join(missing))
remaining_body = u'\n'.join(body_lines[i:]).strip()
return (remaining_body, dictionary)
+
def _strip_footer(self, body):
body_lines = body.splitlines()
- for i,line in enumerate(body_lines):
+ for i, line in enumerate(body_lines):
if line.startswith(BREAK):
break
- i += 1 # increment past the current valid line.
+ i += 1 # increment past the current valid line.
return u'\n'.join(body_lines[:i]).strip()
+
def parse(self):
"""
Parse the commands given in the email. Raises assorted
@@ -474,7 +522,7 @@ class Message (object):
otherwise returns a list of suggested commands to run.
"""
self.validate_subject()
- tag_type,value = self._subject_tag_type()
+ tag_type, value = self._subject_tag_type()
if tag_type == u'new':
commands = self.parse_new()
elif tag_type == u'comment':
@@ -482,18 +530,19 @@ class Message (object):
elif tag_type == u'control':
commands = self.parse_control()
else:
- raise Exception, u'Unrecognized tag type "%s"' % tag_type
+ raise Exception(u'Unrecognized tag type "%s"' % tag_type)
return commands
+
def parse_new(self):
command = u'new'
- tag,subject = self._split_subject()
+ tag, subject = self._split_subject()
summary = subject
options = {u'Reporter': self.author_addr(),
u'Confirm': self._yes_no(self.confirm),
u'Subscribe': 'no',
}
- body,mime_type = list(self._get_bodies_and_mime_types())[0]
- comment_body,options = \
+ body, mime_type = list(self._get_bodies_and_mime_types())[0]
+ comment_body, options = \
self._parse_body_pseudoheaders(body,
NEW_REQUIRED_PSEUDOHEADERS,
NEW_OPTIONAL_PSEUDOHEADERS,
@@ -512,16 +561,16 @@ class Message (object):
comment_body = self._strip_footer(comment_body)
if len(comment_body) > 0:
command = u'comment'
- comment = u'Version: %s\n\n'%options[u'Version'] + comment_body
+ comment = u'Version: %s\n\n' % options[u'Version'] + comment_body
args = [u'--author', self.author_addr(),
u'--alt-id', self.message_id(),
u'--content-type', mime_type]
args.append(id)
args.append(u'-')
commands.append(Command(self, u'comment', args, stdin=comment))
- for key,value in options.items():
+ for key, value in options.items():
if key in [u'Version', u'Reporter', u'Confirm']:
- continue # we've already handled these options
+ continue # we've already handled these options
command = key.lower()
if key in [u'Depend', u'Tag', u'Target', u'Subscribe']:
args = [id, value]
@@ -533,23 +582,25 @@ class Message (object):
args = ['--subscriber', self.author_addr(), id]
commands.append(Command(self, command, args))
return commands
+
def parse_comment(self, bug_uuid):
command = u'comment'
bug_id = bug_uuid
author = self.author_addr()
alt_id = self.message_id()
- body,mime_type = list(self._get_bodies_and_mime_types())[0]
+ body, mime_type = list(self._get_bodies_and_mime_types())[0]
if mime_type == 'text/plain':
body = self._strip_footer(body)
content_type = mime_type
args = [u'--author', author]
- if alt_id != None:
+ if alt_id is not None:
args.extend([u'--alt-id', alt_id])
args.extend([u'--content-type', content_type, bug_id, u'-'])
commands = [Command(self, command, args, stdin=body)]
return commands
+
def parse_control(self):
- body,mime_type = list(self._get_bodies_and_mime_types())[0]
+ body, mime_type = list(self._get_bodies_and_mime_types())[0]
commands = []
for line in body.splitlines():
line = line.strip()
@@ -564,42 +615,46 @@ class Message (object):
if type(line) == types.UnicodeType:
# work around http://bugs.python.org/issue1170
for field in fields:
- field = unicode(field, 'unicode escape')
- command,args = (fields[0], fields[1:])
+ field = str(field, 'unicode escape')
+ command, args = (fields[0], fields[1:])
commands.append(Command(self, command, args))
if len(commands) == 0:
raise InvalidEmail(self, u'No commands in control email.')
return commands
+
def run(self, repo='.'):
self._begin_response()
commands = self.parse()
try:
- for i,command in enumerate(commands):
+ for i, command in enumerate(commands):
command.run()
self._add_response(command.response_msg())
finally:
if AUTOCOMMIT == True:
- tag,subject = self._split_subject()
+ tag, subject = self._split_subject()
self.commit_command = Command(self, 'commit', [subject])
self.commit_command.run()
- if LOGFILE != None:
+ if LOGFILE is not None:
LOGFILE.write(u'Autocommit:\n%s\n\n' %
- send_pgp_mime.flatten(self.commit_command.response_msg(),
- to_unicode=True))
+ send_pgp_mime.flatten(self.commit_command.response_msg(),
+ to_unicode=True))
+
def _begin_response(self):
- tag,subject = self._split_subject()
+ tag, subject = self._split_subject()
response_header = [u'From: %s' % THIS_ADDRESS,
u'To: %s' % self.author_addr(),
u'Date: %s' % libbe.util.utility.time_to_str(time.time()),
- u'Subject: %s Re: %s'%(SUBJECT_TAG_RESPONSE,subject)
+ u'Subject: %s Re: %s' % (SUBJECT_TAG_RESPONSE, subject)
]
- if self.message_id() != None:
+ if self.message_id() is not None:
response_header.append(u'In-reply-to: %s' % self.message_id())
self.response_header = \
send_pgp_mime.header_from_text(text=u'\n'.join(response_header))
self._response_messages = []
+
def _add_response(self, response_message):
self._response_messages.append(response_message)
+
def response_email(self):
assert len(self._response_messages) > 0
if len(self._response_messages) == 1:
@@ -609,9 +664,10 @@ class Message (object):
for message in self._response_messages:
response_body.attach(message)
return send_pgp_mime.attach_root(self.response_header, response_body)
+
def subscriber_emails(self, previous_revision=None):
- if previous_revision == None:
- if AUTOCOMMIT != True: # no way to tell what's changed
+ if previous_revision is None:
+ if AUTOCOMMIT != True: # no way to tell what's changed
raise NotificationFailed('Autocommit dissabled')
if len(self._response_messages) == 0:
raise NotificationFailed('Initial email failed.')
@@ -622,7 +678,7 @@ class Message (object):
bd = UI.storage_callbacks.get_bugdir()
writeable = bd.storage.writeable
bd.storage.writeable = False
- if bd.storage.versioned == False: # no way to tell what's changed
+ if bd.storage.versioned == False: # no way to tell what's changed
bd.storage.writeable = writeable
raise NotificationFailed('Not versioned')
@@ -631,12 +687,12 @@ class Message (object):
if len(subscribers) == 0:
bd.storage.writeable = writeable
return []
- for subscriber,subscriptions in subscribers.items():
+ for subscriber, subscriptions in subscribers.items():
subscribers[subscriber] = []
- for id,types in subscriptions.items():
+ for id, types in subscriptions.items():
for type in types:
subscribers[subscriber].append(
- libbe.diff.Subscription(id,type))
+ libbe.diff.Subscription(id, type))
before_bd, after_bd = self._get_before_and_after_bugdirs(bd, previous_revision)
diff = Diff(before_bd, after_bd)
@@ -644,41 +700,43 @@ class Message (object):
header = self._subscriber_header(bd, previous_revision)
emails = []
- for subscriber,subscriptions in subscribers.items():
+ for subscriber, subscriptions in subscribers.items():
header.replace_header('to', subscriber)
report = diff.report_tree(subscriptions, diff_tree=DiffTree)
root = report.report_or_none()
- if root != None:
+ if root is not None:
emails.append(send_pgp_mime.attach_root(header, root))
- if LOGFILE != None:
+ if LOGFILE is not None:
LOGFILE.write(u'Preparing to notify %s of changes\n' % subscriber)
bd.storage.writeable = writeable
return emails
+
def _get_before_and_after_bugdirs(self, bd, previous_revision=None):
- if previous_revision == None:
+ if previous_revision is None:
commit_msg = self.commit_command.stdout
assert commit_msg.startswith('Committed '), commit_msg
after_revision = commit_msg[len('Committed '):]
before_revision = bd.storage.revision_id(-2)
else:
before_revision = previous_revision
- if before_revision == None:
+ if before_revision is None:
# this commit was the initial commit
before_bd = libbe.bugdir.BugDir(from_disk=False,
manipulate_encodings=False)
else:
before_bd = libbe.bugdir.RevisionedBugDir(bd, before_revision)
- #after_bd = bd.duplicate_bugdir(after_revision)
- after_bd = bd # assume no changes since commit a few cycles ago
+ # after_bd = bd.duplicate_bugdir(after_revision)
+ after_bd = bd # assume no changes since commit a few cycles ago
return (before_bd, after_bd)
+
def _subscriber_header(self, bd, previous_revision=None):
root_dir = os.path.basename(bd.storage.repo)
- if previous_revision == None:
+ if previous_revision is None:
subject = 'Changes to %s on %s by %s' \
- % (root_dir, THIS_SERVER, self.author_addr())
+ % (root_dir, THIS_SERVER, self.author_addr())
else:
subject = 'Changes to %s on %s since revision %s' \
- % (root_dir, THIS_SERVER, previous_revision)
+ % (root_dir, THIS_SERVER, previous_revision)
header = [u'From: %s' % THIS_ADDRESS,
u'To: %s' % u'DUMMY-AUTHOR',
u'Date: %s' % libbe.util.utility.time_to_str(time.time()),
@@ -686,6 +744,7 @@ class Message (object):
]
return send_pgp_mime.header_from_text(text=u'\n'.join(header))
+
def generate_global_tags(tag_base=u'be-bug'):
"""
Generate a series of tags from a base tag string.
@@ -699,6 +758,7 @@ def generate_global_tags(tag_base=u'be-bug'):
SUBJECT_TAG_COMMENT = re.compile(u'\[%s:([\-0-9a-z/]*)]' % tag_base)
SUBJECT_TAG_CONTROL = SUBJECT_TAG_RESPONSE
+
def open_logfile(logpath=None):
"""
If logpath=None, default to global LOGPATH.
@@ -708,7 +768,7 @@ def open_logfile(logpath=None):
Relative logpaths are expanded relative to _THIS_DIR
"""
global LOGPATH, LOGFILE
- if logpath != None:
+ if logpath is not None:
if logpath == u'-':
LOGPATH = u'stderr'
LOGFILE = sys.stderr
@@ -719,14 +779,16 @@ def open_logfile(logpath=None):
LOGPATH = logpath
else:
LOGPATH = os.path.join(_THIS_DIR, logpath)
- if LOGFILE == None and LOGPATH != u'none':
+ if LOGFILE is None and LOGPATH != u'none':
LOGFILE = codecs.open(LOGPATH, u'a+',
- libbe.util.encoding.get_text_file_encoding())
+ libbe.util.encoding.get_text_file_encoding())
+
def close_logfile():
- if LOGFILE != None and LOGPATH not in [u'stderr', u'none']:
+ if LOGFILE is not None and LOGPATH not in [u'stderr', u'none']:
LOGFILE.close()
+
def test():
result = unittest.TextTestRunner(verbosity=2).run(suite)
num_errors = len(result.errors)
@@ -734,11 +796,12 @@ def test():
num_bad = num_errors + num_failures
return num_bad
+
def main(args):
from optparse import OptionParser
global AUTOCOMMIT, UI
- usage='be-handle-mail [options]\n\n%s' % (__doc__)
+ usage = 'be-handle-mail [options]\n\n%s' % (__doc__)
parser = OptionParser(usage=usage)
parser.add_option('-r', '--repo', dest='repo', default=_THIS_DIR,
metavar='REPO',
@@ -762,17 +825,17 @@ def main(args):
help='Run internal unit-tests and exit.')
pargs = args
- options,args = parser.parse_args(args[1:])
+ options, args = parser.parse_args(args[1:])
if options.test == True:
num_bad = test()
if num_bad > 126:
num_bad = 1
sys.exit(num_bad)
-
+
AUTOCOMMIT = options.autocommit
- if options.notify_since == None:
+ if options.notify_since is None:
msg_text = sys.stdin.read()
open_logfile(options.logfile)
@@ -781,29 +844,29 @@ def main(args):
io = libbe.command.StringInputOutput()
UI = libbe.command.UserInterface(io, location=options.repo)
- if options.notify_since != None:
+ if options.notify_since is not None:
if options.subscribers == True:
- if LOGFILE != None:
+ if LOGFILE is not None:
LOGFILE.write(u'Checking for subscribers to notify since revision %s\n'
% options.notify_since)
try:
m = Message(disable_parsing=True)
emails = m.subscriber_emails(options.notify_since)
- except NotificationFailed, e:
- if LOGFILE != None:
- LOGFILE.write(unicode(e) + u'\n')
+ except NotificationFailed as e:
+ if LOGFILE is not None:
+ LOGFILE.write(str(e) + u'\n')
else:
for msg in emails:
if options.output == True:
- print send_pgp_mime.flatten(msg, to_unicode=True)
+ print(send_pgp_mime.flatten(msg, to_unicode=True))
else:
send_pgp_mime.mail(msg, send_pgp_mime.sendmail)
close_logfile()
UI.cleanup()
sys.exit(0)
- if len(msg_text.strip()) == 0: # blank email!?
- if LOGFILE != None:
+ if len(msg_text.strip()) == 0: # blank email!?
+ if LOGFILE is not None:
LOGFILE.write(u'Blank email!\n')
close_logfile()
UI.cleanup()
@@ -811,10 +874,10 @@ def main(args):
try:
m = Message(msg_text)
m.run()
- except InvalidEmail, e:
+ except InvalidEmail as e:
response = e.response()
- except Exception, e:
- if LOGFILE != None:
+ except Exception as e:
+ if LOGFILE is not None:
LOGFILE.write(u'Uncaught exception:\n%s\n' % (e,))
traceback.print_tb(sys.exc_traceback, file=LOGFILE)
close_logfile()
@@ -824,28 +887,28 @@ def main(args):
else:
response = m.response_email()
if options.output == True:
- print send_pgp_mime.flatten(response, to_unicode=True)
+ print(send_pgp_mime.flatten(response, to_unicode=True))
elif m.confirm == True:
- if LOGFILE != None:
+ if LOGFILE is not None:
LOGFILE.write(u'Sending response to %s\n' % m.author_addr())
LOGFILE.write(u'\n%s\n\n' % send_pgp_mime.flatten(response,
to_unicode=True))
send_pgp_mime.mail(response, send_pgp_mime.sendmail)
else:
- if LOGFILE != None:
+ if LOGFILE is not None:
LOGFILE.write(u'Response declined by %s\n' % m.author_addr())
if options.subscribers == True:
- if LOGFILE != None:
+ if LOGFILE is not None:
LOGFILE.write(u'Checking for subscribers\n')
try:
emails = m.subscriber_emails()
- except NotificationFailed, e:
- if LOGFILE != None:
- LOGFILE.write(unicode(e) + u'\n')
+ except NotificationFailed as e:
+ if LOGFILE is not None:
+ LOGFILE.write(str(e) + u'\n')
else:
for msg in emails:
if options.output == True:
- print send_pgp_mime.flatten(msg, to_unicode=True)
+ print(send_pgp_mime.flatten(msg, to_unicode=True))
else:
send_pgp_mime.mail(msg, send_pgp_mime.sendmail)
@@ -853,23 +916,28 @@ def main(args):
m.commit_command.cleanup()
UI.cleanup()
-class GenerateGlobalTagsTestCase (unittest.TestCase):
+
+class GenerateGlobalTagsTestCase(unittest.TestCase):
def setUp(self):
super(GenerateGlobalTagsTestCase, self).setUp()
self.save_global_tags()
+
def tearDown(self):
self.restore_global_tags()
super(GenerateGlobalTagsTestCase, self).tearDown()
+
def save_global_tags(self):
self.saved_globals = [SUBJECT_TAG_BASE, SUBJECT_TAG_START,
SUBJECT_TAG_RESPONSE, SUBJECT_TAG_NEW,
SUBJECT_TAG_COMMENT, SUBJECT_TAG_CONTROL]
+
def restore_global_tags(self):
global SUBJECT_TAG_BASE, SUBJECT_TAG_START, SUBJECT_TAG_RESPONSE, \
SUBJECT_TAG_NEW, SUBJECT_TAG_COMMENT, SUBJECT_TAG_CONTROL
SUBJECT_TAG_BASE, SUBJECT_TAG_START, SUBJECT_TAG_RESPONSE, \
SUBJECT_TAG_NEW, SUBJECT_TAG_COMMENT, SUBJECT_TAG_CONTROL = \
self.saved_globals
+
def test_restore_global_tags(self):
"Test global tag restoration by teardown function."
global SUBJECT_TAG_BASE
@@ -878,26 +946,32 @@ class GenerateGlobalTagsTestCase (unittest.TestCase):
self.failUnlessEqual(SUBJECT_TAG_BASE, u'projectX-bug')
self.restore_global_tags()
self.failUnlessEqual(SUBJECT_TAG_BASE, u'be-bug')
+
def test_subject_tag_base(self):
"Should set SUBJECT_TAG_BASE global correctly"
generate_global_tags(u'projectX-bug')
self.failUnlessEqual(SUBJECT_TAG_BASE, u'projectX-bug')
+
def test_subject_tag_start(self):
"Should set SUBJECT_TAG_START global correctly"
generate_global_tags(u'projectX-bug')
self.failUnlessEqual(SUBJECT_TAG_START, u'[projectX-bug')
+
def test_subject_tag_response(self):
"Should set SUBJECT_TAG_RESPONSE global correctly"
generate_global_tags(u'projectX-bug')
self.failUnlessEqual(SUBJECT_TAG_RESPONSE, u'[projectX-bug]')
+
def test_subject_tag_new(self):
"Should set SUBJECT_TAG_NEW global correctly"
generate_global_tags(u'projectX-bug')
self.failUnlessEqual(SUBJECT_TAG_NEW, u'[projectX-bug:submit]')
+
def test_subject_tag_control(self):
"Should set SUBJECT_TAG_CONTROL global correctly"
generate_global_tags(u'projectX-bug')
self.failUnlessEqual(SUBJECT_TAG_CONTROL, u'[projectX-bug]')
+
def test_subject_tag_comment(self):
"Should set SUBJECT_TAG_COMMENT global correctly"
generate_global_tags(u'projectX-bug')
@@ -905,6 +979,7 @@ class GenerateGlobalTagsTestCase (unittest.TestCase):
self.failUnlessEqual(len(m.groups()), 1)
self.failUnlessEqual(m.group(1), u'abc/xyz-123')
+
unitsuite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()])
diff --git a/interfaces/email/interactive/send_pgp_mime.py b/interfaces/email/interactive/send_pgp_mime.py
index 42a0a8c..c70da23 100644
--- a/interfaces/email/interactive/send_pgp_mime.py
+++ b/interfaces/email/interactive/send_pgp_mime.py
@@ -128,7 +128,7 @@ def mail(msg, sendmail=None):
the local host doesn't have an SMTP server set up
for easy smtplib usage.
"""
- if sendmail != None:
+ if sendmail is not None:
execute(sendmail, stdin=flatten(msg))
return None
s = smtplib.SMTP()
@@ -167,11 +167,11 @@ def guess_encoding(text):
pass
else:
break
- assert encoding != None
+ assert encoding is not None
return encoding
def encodedMIMEText(body, encoding=None):
- if encoding == None:
+ if encoding is None:
encoding = guess_encoding(body)
if encoding == "us-ascii":
return MIMEText(body)
@@ -223,7 +223,7 @@ def replace(template, format_char, replacement_text):
>>> replace('--textmode %?a?-u %a? %f', 'a', '')
'--textmode %f'
"""
- if replacement_text == None:
+ if replacement_text is None:
replacement_text = ""
regexp = re.compile('%[?]'+format_char+'[?]([^?]*)[?]')
if len(replacement_text) > 0:
@@ -238,7 +238,7 @@ def flatten(msg, to_unicode=False):
"""
Produce flat text output from an email Message instance.
"""
- assert msg != None
+ assert msg is not None
fp = StringIO()
g = Generator(fp, mangle_from_=False)
g.flatten(msg)
@@ -392,9 +392,9 @@ class PGPMimeMessageFactory (object):
body.add_header('Content-Disposition', 'inline')
return body
def passphrase_arg(self, passphrase=None):
- if passphrase == None and PASSPHRASE != None:
+ if passphrase is None and PASSPHRASE is not None:
passphrase = PASSPHRASE
- if passphrase == None:
+ if passphrase is None:
return (None,'')
return (passphrase, pgp_stdin_passphrase_arg)
def plain(self):
@@ -415,7 +415,7 @@ class PGPMimeMessageFactory (object):
bfile.flush()
args = replace(pgp_sign_command, 'f', bfile.name)
- if PGP_SIGN_AS == None:
+ if PGP_SIGN_AS is None:
pgp_sign_as = '<%s>' % source_email(header)
else:
pgp_sign_as = PGP_SIGN_AS
@@ -453,7 +453,7 @@ class PGPMimeMessageFactory (object):
recipient_string = ' '.join(recipients)
args = replace(pgp_encrypt_only_command, 'R', recipient_string)
args = replace(args, 'f', bfile.name)
- if PGP_SIGN_AS == None:
+ if PGP_SIGN_AS is None:
pgp_sign_as = '<%s>' % source_email(header)
else:
pgp_sign_as = PGP_SIGN_AS
@@ -493,7 +493,7 @@ class PGPMimeMessageFactory (object):
recipient_string = ' '.join(recipients)
args = replace(pgp_encrypt_only_command, 'R', recipient_string)
args = replace(args, 'f', bfile.name)
- if PGP_SIGN_AS == None:
+ if PGP_SIGN_AS is None:
pgp_sign_as = '<%s>' % source_email(header)
else:
pgp_sign_as = PGP_SIGN_AS
@@ -556,9 +556,9 @@ if __name__ == '__main__':
stdin_used = False
- if options.passphrase_file != None:
+ if options.passphrase_file is not None:
PASSPHRASE = file(options.passphrase_file, 'r').read()
- elif options.passphrase_fd != None:
+ elif options.passphrase_fd is not None:
if options.passphrase_fd == 0:
stdin_used = True
PASSPHRASE = sys.stdin.read()
@@ -573,25 +573,25 @@ if __name__ == '__main__':
sys.exit(0)
header = None
- if options.header_filename != None:
+ if options.header_filename is not None:
if options.header_filename == '-':
assert stdin_used == False
stdin_used = True
header = sys.stdin.read()
else:
header = file(options.header_filename, 'r').read()
- if header == None:
+ if header is None:
raise Exception("missing header")
headermsg = header_from_text(header)
body = None
- if options.body_filename != None:
+ if options.body_filename is not None:
if options.body_filename == '-':
assert stdin_used == False
stdin_used = True
body = sys.stdin.read()
else:
body = file(options.body_filename, 'r').read()
- if body == None:
+ if body is None:
raise Exception("missing body")
m = PGPMimeMessageFactory(body)
diff --git a/interfaces/web/web.py b/interfaces/web/web.py
index ed87c78..ba68908 100644
--- a/interfaces/web/web.py
+++ b/interfaces/web/web.py
@@ -75,13 +75,13 @@ class WebInterface:
if target != '':
target = None if target == 'None' else target
- if target == None:
+ if target is None:
# Return all bugs that don't block any targets.
return [bug for bug in bugs if not bug_target(self.bd, bug)]
else:
# Return all bugs that block the supplied target.
targetbug = bug_from_target_summary(self.bd, target)
- if targetbug == None:
+ if targetbug is None:
return []
bugs = [bug for bug in get_blocked_by(self.bd, targetbug) if
bug.active]
@@ -188,7 +188,7 @@ class WebInterface:
"""The view that handles editing bug details."""
bug = self.bd.bug_from_uuid(id)
- if summary != None:
+ if summary is not None:
bug.summary = summary
else:
bug.status = status if status != 'None' else None
diff --git a/libbe/bugdir.py b/libbe/bugdir.py
index a5d384d..a694e89 100644
--- a/libbe/bugdir.py
+++ b/libbe/bugdir.py
@@ -133,8 +133,8 @@ class BugDir (list, settings_object.SavedSettingsObject):
def inactive_status(): return {}
def _extra_strings_check_fn(value):
- return utility.iterable_full_of_strings(value, \
- alternative=settings_object.EMPTY)
+ return utility.iterable_full_of_strings(value,
+ alternative=settings_object.EMPTY)
def _extra_strings_change_hook(self, old, new):
self.extra_strings.sort() # to make merging easier
self._prop_save_settings(old, new)
@@ -175,7 +175,7 @@ class BugDir (list, settings_object.SavedSettingsObject):
else:
if self.uuid is None:
self.uuid = libbe.util.id.uuid_gen()
- if self.storage != None and self.storage.is_writeable():
+ if self.storage is not None and self.storage.is_writeable():
self.save()
# methods for saving/loading/accessing settings and properties.
@@ -235,7 +235,7 @@ class BugDir (list, settings_object.SavedSettingsObject):
def _refresh_uuid_cache(self):
self._uuids_cache = set()
# list bugs that are in storage
- if self.storage != None and self.storage.is_readable():
+ if self.storage is not None and self.storage.is_readable():
child_uuids = libbe.util.id.child_uuids(
self.storage.children(self.id.storage()))
for id in child_uuids:
@@ -274,7 +274,7 @@ class BugDir (list, settings_object.SavedSettingsObject):
if hasattr(self, '_uuids_cache') and bug.uuid in self._uuids_cache:
self._uuids_cache.remove(bug.uuid)
self.remove(bug)
- if self.storage != None and self.storage.is_writeable():
+ if self.storage is not None and self.storage.is_writeable():
bug.remove()
def bug_from_uuid(self, uuid):
@@ -752,12 +752,12 @@ if libbe.TESTING:
bug_b.creator = 'Jane Doe <jdoe@example.com>'
bug_b.time = 0
bug_b.status = 'closed'
- if self.storage != None:
+ if self.storage is not None:
self.storage.disconnect() # flush to storage
self.storage.connect()
def cleanup(self):
- if self.storage != None:
+ if self.storage is not None:
self.storage.writeable = True
self.storage.disconnect()
self.storage.destroy()
@@ -765,7 +765,7 @@ if libbe.TESTING:
self._dir_ref.cleanup()
def flush_reload(self):
- if self.storage != None:
+ if self.storage is not None:
self.storage.disconnect()
self.storage.connect()
self._clear_bugs()
@@ -885,7 +885,7 @@ if libbe.TESTING:
self.storage.disconnect()
self.storage.connect()
def tearDown(self):
- if self.storage != None:
+ if self.storage is not None:
self.storage.disconnect()
self.storage.destroy()
self.dir.cleanup()
diff --git a/libbe/command/base.py b/libbe/command/base.py
index 806d880..b6a9e15 100644
--- a/libbe/command/base.py
+++ b/libbe/command/base.py
@@ -74,7 +74,7 @@ def get_command(command_name):
>>> try:
... get_command('asdf')
- ... except UnknownCommand, e:
+ ... except UnknownCommand as e:
... print(e)
Unknown command 'asdf'
(No module named asdf)
@@ -99,7 +99,7 @@ def get_command_class(module=None, command_name=None):
>>> repr(import_xml)
"<class 'libbe.command.import_xml.Import_XML'>"
"""
- if module == None:
+ if module is None:
module = get_command(command_name)
try:
cname = command_name.capitalize().replace('-', '_')
@@ -121,7 +121,7 @@ def modname_to_command_name(modname):
... try:
... if issubclass(attr, Command):
... commands.append(attr)
- ... except TypeError, e:
+ ... except TypeError as e:
... pass
... if len(commands) == 0:
... raise Exception('No Command classes in %s' % dir(mod))
@@ -163,7 +163,7 @@ class Argument (CommandInput):
self.optional = optional
self.repeatable = repeatable
self.completion_callback = completion_callback
- if self.metavar == None:
+ if self.metavar is None:
self.metavar = self.name.upper()
class Option (CommandInput):
@@ -173,17 +173,17 @@ class Option (CommandInput):
self.callback = callback
self.short_name = short_name
self.arg = arg
- if self.arg == None and self.callback == None:
+ if self.arg is None and self.callback is None:
# use an implicit boolean argument
self.arg = Argument(name=self.name, help=self.help,
default=False, type='bool')
self.validate()
def validate(self):
- if self.arg == None:
- assert self.callback != None, self.name
+ if self.arg is None:
+ assert self.callback is not None, self.name
return
- assert self.callback == None, '%s: %s' % (self.name, self.callback)
+ assert self.callback is None, '%s: %s' % (self.name, self.callback)
assert self.arg.name == self.name, \
'Name missmatch: %s != %s' % (self.arg.name, self.name)
assert self.arg.optional == False, self.name
@@ -208,13 +208,13 @@ class _DummyParser (optparse.OptionParser):
# from libbe.ui.command_line.CmdOptionParser._add_option
option.validate()
long_opt = '--%s' % option.name
- if option.short_name != None:
+ if option.short_name is not None:
short_opt = '-%s' % option.short_name
assert '_' not in option.name, \
'Non-reconstructable option name %s' % option.name
kwargs = {'dest':option.name.replace('-', '_'),
'help':option.help}
- if option.arg == None or option.arg.type == 'bool':
+ if option.arg is None or option.arg.type == 'bool':
kwargs['action'] = 'store_true'
kwargs['metavar'] = None
kwargs['default'] = False
@@ -223,7 +223,7 @@ class _DummyParser (optparse.OptionParser):
kwargs['action'] = 'store'
kwargs['metavar'] = option.arg.metavar
kwargs['default'] = option.arg.default
- if option.short_name != None:
+ if option.short_name is not None:
opt = optparse.Option(short_opt, long_opt, **kwargs)
else:
opt = optparse.Option(long_opt, **kwargs)
@@ -291,7 +291,7 @@ class Command (object):
pass
else:
params.pop('help')
- if params['complete'] != None:
+ if params['complete'] is not None:
pass
else:
params.pop('complete')
@@ -303,16 +303,16 @@ class Command (object):
return self.status
def _parse_options_args(self, options=None, args=None):
- if options == None:
+ if options is None:
options = {}
- if args == None:
+ if args is None:
args = []
params = {}
for option in self.options:
assert option.name not in params, params[option.name]
if option.name in options:
params[option.name] = options.pop(option.name)
- elif option.arg != None:
+ elif option.arg is not None:
params[option.name] = option.arg.default
else: # non-arg options are flags, set to default flag value
params[option.name] = False
@@ -385,13 +385,13 @@ class Command (object):
return "A detailed help message."
def complete(self, argument=None, fragment=None):
- if argument == None:
+ if argument is None:
ret = ['--%s' % o.name for o in self.options
if o.name != 'complete']
- if len(self.args) > 0 and self.args[0].completion_callback != None:
+ if len(self.args) > 0 and self.args[0].completion_callback is not None:
ret.extend(self.args[0].completion_callback(self, argument, fragment))
return ret
- elif argument.completion_callback != None:
+ elif argument.completion_callback is not None:
# finish a particular argument
return argument.completion_callback(self, argument, fragment)
return [] # the particular argument doesn't supply completion info
@@ -413,7 +413,7 @@ class Command (object):
>>> c = Command()
>>> try:
... c._check_restricted_access(s, os.path.expanduser('~/.ssh/id_rsa'))
- ... except UserError, e:
+ ... except UserError as e:
... assert str(e).startswith('file access restricted!'), str(e)
... print('we got the expected error')
we got the expected error
@@ -457,9 +457,9 @@ class StdInputOutput (InputOutput):
InputOutput.__init__(self, stdin, stdout)
def _get_io(self, input_encoding=None, output_encoding=None):
- if input_encoding == None:
+ if input_encoding is None:
input_encoding = libbe.util.encoding.get_input_encoding()
- if output_encoding == None:
+ if output_encoding is None:
output_encoding = libbe.util.encoding.get_output_encoding()
stdin = codecs.getreader(input_encoding)(sys.stdin)
stdin.encoding = input_encoding
@@ -512,7 +512,7 @@ class UnconnectedStorageGetter (object):
class StorageCallbacks (object):
def __init__(self, location=None):
- if location == None:
+ if location is None:
location = '.'
self.location = location
self._get_unconnected_storage = UnconnectedStorageGetter(location)
@@ -532,7 +532,7 @@ class StorageCallbacks (object):
intended for the init command, which calls Storage.init().
"""
if not hasattr(self, '_unconnected_storage'):
- if self._get_unconnected_storage == None:
+ if self._get_unconnected_storage is None:
raise NotImplementedError
self._unconnected_storage = self._get_unconnected_storage()
return self._unconnected_storage
@@ -574,7 +574,7 @@ class StorageCallbacks (object):
class UserInterface (object):
def __init__(self, io=None, location=None):
- if io == None:
+ if io is None:
io = StringInputOutput()
self.io = io
self.storage_callbacks = StorageCallbacks(location)
diff --git a/libbe/command/comment.py b/libbe/command/comment.py
index bfd24fe..c579610 100644
--- a/libbe/command/comment.py
+++ b/libbe/command/comment.py
@@ -126,7 +126,7 @@ class Comment (libbe.command.Command):
bugdir,bug,parent = (
libbe.command.util.bugdir_bug_comment_from_user_id(
bugdirs, params['id']))
- if params['comment'] == None:
+ if params['comment'] is None:
# try to launch an editor for comment-body entry
try:
if parent == bug.comment_root:
@@ -144,7 +144,7 @@ class Comment (libbe.command.Command):
if body is None:
raise libbe.command.UserError('No comment entered.')
elif params['comment'] == '-': # read body from stdin
- binary = not (params['content-type'] == None
+ binary = not (params['content-type'] is None
or params['content-type'].startswith("text/"))
if not binary:
body = self.stdin.read()
@@ -156,12 +156,12 @@ class Comment (libbe.command.Command):
body = params['comment']
if not body.endswith('\n'):
body+='\n'
- if params['author'] == None:
+ if params['author'] is None:
params['author'] = self._get_user_id()
new = parent.new_reply(body=body, content_type=params['content-type'])
for key in ['alt-id', 'author']:
- if params[key] != None:
+ if params[key] is not None:
setattr(new, new._setting_name_to_attr_name(key), params[key])
if params['full-uuid']:
comment_id = new.id.long_user()
diff --git a/libbe/command/commit.py b/libbe/command/commit.py
index 077980d..afe082d 100644
--- a/libbe/command/commit.py
+++ b/libbe/command/commit.py
@@ -71,10 +71,10 @@ class Commit (libbe.command.Command):
summary = sys.stdin.readline()
else:
summary = params['summary']
- if summary == None and params['body'] == None:
+ if summary is None and params['body'] is None:
params['body'] = 'EDITOR'
storage = self._get_storage()
- if params['body'] == None:
+ if params['body'] is None:
body = None
elif params['body'] == 'EDITOR':
body = libbe.ui.util.editor.editor_string(
@@ -83,8 +83,8 @@ class Commit (libbe.command.Command):
self._check_restricted_access(storage, params['body'])
body = libbe.util.encoding.get_file_contents(
params['body'], decode=True)
- if summary == None: # use the first body line as the summary
- if body == None:
+ if summary is None: # use the first body line as the summary
+ if body is None:
raise libbe.command.UserError(
'cannot commit without a summary')
lines = body.splitlines()
diff --git a/libbe/command/depend.py b/libbe/command/depend.py
index 4cb0efd..fe02ce0 100644
--- a/libbe/command/depend.py
+++ b/libbe/command/depend.py
@@ -54,7 +54,7 @@ class Filter (object):
else:
target_bug = libbe.command.target.bug_target(bugdirs, bug)
if self.target in ['none', None]:
- if target_bug.summary != None:
+ if target_bug.summary is not None:
return False
else:
if target_bug.summary != self.target:
@@ -195,14 +195,14 @@ class Depend (libbe.command.Command):
])
def _run(self, **params):
- if params['repair'] == True and params['bug-id'] != None:
+ if params['repair'] == True and params['bug-id'] is not None:
raise libbe.command.UserError(
'No arguments with --repair calls.')
- if params['repair'] == False and params['bug-id'] == None:
+ if params['repair'] == False and params['bug-id'] is None:
raise libbe.command.UserError(
'Must specify either --repair or a BUG-ID')
- if params['tree-depth'] != None \
- and params['blocking-bug-id'] != None:
+ if params['tree-depth'] is not None \
+ and params['blocking-bug-id'] is not None:
raise libbe.command.UserError(
'Only one bug id used in tree mode.')
bugdirs = self._get_bugdirs()
@@ -223,7 +223,7 @@ class Depend (libbe.command.Command):
libbe.command.util.bugdir_bug_comment_from_user_id(
bugdirs, params['bug-id']))
- if params['tree-depth'] != None:
+ if params['tree-depth'] is not None:
dtree = DependencyTree(bugdirs, bugA, params['tree-depth'], filter)
if len(dtree.blocked_by_tree()) > 0:
print('%s blocked by:' % bugA.id.user(), file=self.stdout)
@@ -241,7 +241,7 @@ class Depend (libbe.command.Command):
% (' '*(depth), self.bug_string(node.bug, params))), file=self.stdout)
return 0
- if params['blocking-bug-id'] != None:
+ if params['blocking-bug-id'] is not None:
bugdirB,bugB,dummy_comment = (
libbe.command.util.bugdir_bug_comment_from_user_id(
bugdirs, params['blocking-bug-id']))
diff --git a/libbe/command/diff.py b/libbe/command/diff.py
index d8aea37..aca54c3 100644
--- a/libbe/command/diff.py
+++ b/libbe/command/diff.py
@@ -97,18 +97,18 @@ class Diff (libbe.command.Command):
def diff(self, bugdir, subscriptions, params):
- if params['repo'] == None:
+ if params['repo'] is None:
if bugdir.storage.versioned == False:
raise libbe.command.UserError(
'This repository is not revision-controlled.')
- if params['revision'] == None: # get the most recent revision
+ if params['revision'] is None: # get the most recent revision
params['revision'] = bugdir.storage.revision_id(-1)
old_bd = libbe.bugdir.RevisionedBugDir(bugdir, params['revision'])
else:
old_storage = libbe.storage.get_storage(params['repo'])
old_storage.connect()
old_bd_current = libbe.bugdir.BugDir(old_storage, from_disk=True)
- if params['revision'] == None: # use the current working state
+ if params['revision'] is None: # use the current working state
old_bd = old_bd_current
else:
if old_bd_current.storage.versioned == False:
@@ -127,7 +127,7 @@ class Diff (libbe.command.Command):
print('\n'.join(uuids), file=self.stdout)
else :
rep = tree.report_string()
- if rep != None:
+ if rep is not None:
print(rep, file=self.stdout)
return 0
diff --git a/libbe/command/due.py b/libbe/command/due.py
index ddf111a..2f7d181 100644
--- a/libbe/command/due.py
+++ b/libbe/command/due.py
@@ -65,7 +65,7 @@ class Due (libbe.command.Command):
bugdir,bug,comment = (
libbe.command.util.bugdir_bug_comment_from_user_id(
bugdirs, params['bug-id']))
- if params['due'] == None:
+ if params['due'] is None:
due_time = get_due(bug)
if due_time is None:
print('No due date assigned.', file=self.stdout)
diff --git a/libbe/command/help.py b/libbe/command/help.py
index 981ea1a..c7961ac 100644
--- a/libbe/command/help.py
+++ b/libbe/command/help.py
@@ -93,7 +93,7 @@ class Help (libbe.command.Command):
])
def _run(self, **params):
- if params['topic'] == None:
+ if params['topic'] is None:
if hasattr(self.ui, 'help'):
print(self.ui.help().rstrip('\n'), file=self.stdout)
elif params['topic'] in libbe.command.commands(command_names=True):
diff --git a/libbe/command/html.py b/libbe/command/html.py
index ed43808..5ec8691 100644
--- a/libbe/command/html.py
+++ b/libbe/command/html.py
@@ -100,21 +100,11 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
self.logger.log(
self.log_level, 'generate {} index file for {} bugs'.format(
bug_type, len(bugs)))
- template_info = {
- 'title': self.title,
- 'charset': 'UTF-8',
- 'stylesheet': 'style.css',
- 'header': self.header,
- 'active_class': 'tab nsel',
- 'inactive_class': 'tab nsel',
- 'target_class': 'tab nsel',
- 'bugs': bugs,
- 'bug_entry': self.template.get_template('index_bug_entry.html'),
- 'bug_dir': self.bug_dir,
- 'index_file': self._index_file,
- 'generation_time': self._generation_time(),
- }
- template_info['{}_class'.format(bug_type)] = 'tab sel'
+ template_info = {'title': self.title, 'charset': 'UTF-8', 'stylesheet': 'style.css', 'header': self.header,
+ 'active_class': 'tab nsel', 'inactive_class': 'tab nsel', 'target_class': 'tab nsel',
+ 'bugs': bugs, 'bug_entry': self.template.get_template('index_bug_entry.html'),
+ 'bug_dir': self.bug_dir, 'index_file': self._index_file,
+ 'generation_time': self._generation_time(), '{}_class'.format(bug_type): 'tab sel'}
if bug_type == 'target':
template = self.template.get_template('target_index.html')
template_info['targets'] = [
@@ -314,7 +304,7 @@ class ServerApp (libbe.util.wsgi.WSGI_AppObject,
return time.ctime()
def _escape(self, string):
- if string == None:
+ if string is None:
return ''
return xml.sax.saxutils.escape(string)
diff --git a/libbe/command/import_xml.py b/libbe/command/import_xml.py
index 391b2ed..42b9b49 100644
--- a/libbe/command/import_xml.py
+++ b/libbe/command/import_xml.py
@@ -102,7 +102,7 @@ class Import_XML (libbe.command.Command):
bugdirs = self._get_bugdirs()
writeable = storage.writeable
storage.writeable = False
- if params['root'] != None:
+ if params['root'] is not None:
root_bugdir,root_bug,root_comment = (
libbe.command.util.bugdir_bug_comment_from_user_id(
bugdirs, params['root']))
@@ -136,7 +136,7 @@ class Import_XML (libbe.command.Command):
comms = []
for c in root_bug.comments():
comms.append(c.uuid)
- if c.alt_id != None:
+ if c.alt_id is not None:
comms.append(c.alt_id)
if root_comment.uuid == libbe.comment.INVALID_UUID:
root_text = root_bug.id.user()
@@ -496,13 +496,13 @@ if libbe.TESTING == True:
c1 = bugB.comment_from_uuid('c1')
comments.remove(c1)
self.assertTrue(c1.uuid == 'c1', c1.uuid)
- self.assertTrue(c1.alt_id == None, c1.alt_id)
+ self.assertTrue(c1.alt_id is None, c1.alt_id)
self.assertTrue(c1.author == 'Jane', c1.author)
self.assertTrue(c1.body == 'So long\n', c1.body)
c2 = bugB.comment_from_uuid('c2')
comments.remove(c2)
self.assertTrue(c2.uuid == 'c2', c2.uuid)
- self.assertTrue(c2.alt_id == None, c2.alt_id)
+ self.assertTrue(c2.alt_id is None, c2.alt_id)
self.assertTrue(c2.author == 'Jess', c2.author)
self.assertTrue(c2.body == 'World\n', c2.body)
c4 = comments[0]
@@ -530,13 +530,13 @@ if libbe.TESTING == True:
c1 = bugB.comment_from_uuid('c1')
comments.remove(c1)
self.assertTrue(c1.uuid == 'c1', c1.uuid)
- self.assertTrue(c1.alt_id == None, c1.alt_id)
+ self.assertTrue(c1.alt_id is None, c1.alt_id)
self.assertTrue(c1.author == 'Jane', c1.author)
self.assertTrue(c1.body == 'Hello\n', c1.body)
c2 = bugB.comment_from_uuid('c2')
comments.remove(c2)
self.assertTrue(c2.uuid == 'c2', c2.uuid)
- self.assertTrue(c2.alt_id == None, c2.alt_id)
+ self.assertTrue(c2.alt_id is None, c2.alt_id)
self.assertTrue(c2.author == 'Jess', c2.author)
self.assertTrue(c2.body == 'World\n', c2.body)
c4 = comments[0]
@@ -566,13 +566,13 @@ if libbe.TESTING == True:
c1 = bugB.comment_from_uuid('c1')
comments.remove(c1)
self.assertTrue(c1.uuid == 'c1', c1.uuid)
- self.assertTrue(c1.alt_id == None, c1.alt_id)
+ self.assertTrue(c1.alt_id is None, c1.alt_id)
self.assertTrue(c1.author == 'Jane', c1.author)
self.assertTrue(c1.body == 'So long\n', c1.body)
c2 = bugB.comment_from_uuid('c2')
comments.remove(c2)
self.assertTrue(c2.uuid == 'c2', c2.uuid)
- self.assertTrue(c2.alt_id == None, c2.alt_id)
+ self.assertTrue(c2.alt_id is None, c2.alt_id)
self.assertTrue(c2.author == 'Jess', c2.author)
self.assertTrue(c2.body == 'World\n', c2.body)
c4 = comments[0]
@@ -601,13 +601,13 @@ if libbe.TESTING == True:
c1 = bugB.comment_from_uuid('c1')
comments.remove(c1)
self.assertTrue(c1.uuid == 'c1', c1.uuid)
- self.assertTrue(c1.alt_id == None, c1.alt_id)
+ self.assertTrue(c1.alt_id is None, c1.alt_id)
self.assertTrue(c1.author == 'Jane', c1.author)
self.assertTrue(c1.body == 'Hello\n', c1.body)
c2 = bugB.comment_from_uuid('c2')
comments.remove(c2)
self.assertTrue(c2.uuid == 'c2', c2.uuid)
- self.assertTrue(c2.alt_id == None, c2.alt_id)
+ self.assertTrue(c2.alt_id is None, c2.alt_id)
self.assertTrue(c2.author == 'Jess', c2.author)
self.assertTrue(c2.body == 'World\n', c2.body)
c4 = comments[0]
diff --git a/libbe/command/list.py b/libbe/command/list.py
index 41e1bed..567e3fe 100644
--- a/libbe/command/list.py
+++ b/libbe/command/list.py
@@ -156,7 +156,7 @@ class List (libbe.command.Command):
def _parse_params(self, bugdirs, params):
cmp_list = []
- if params['sort'] != None:
+ if params['sort'] is not None:
for cmp in params['sort'].split(','):
if cmp not in AVAILABLE_IDXS:
raise libbe.command.UserError(
@@ -167,7 +167,7 @@ class List (libbe.command.Command):
severity = parse_severity(params['severity'],
important=params['important'])
# select assigned
- if params['assigned'] == None:
+ if params['assigned'] is None:
if params['mine'] == True:
assigned = [self._get_user_id()]
else:
@@ -178,7 +178,7 @@ class List (libbe.command.Command):
for i in range(len(assigned)):
if assigned[i] == '-':
assigned[i] = params['user-id']
- if params['extra-strings'] == None:
+ if params['extra-strings'] is None:
extra_strings_regexps = []
else:
extra_strings_regexps = [re.compile(x)
diff --git a/libbe/command/merge.py b/libbe/command/merge.py
index 4ee67cf..5100803 100644
--- a/libbe/command/merge.py
+++ b/libbe/command/merge.py
@@ -170,7 +170,7 @@ class Merge (libbe.command.Command):
for comment in newCommTree.traverse(): # all descendant comments
comment.bug = bugA
# uuids must be unique in storage
- if comment.alt_id == None:
+ if comment.alt_id is None:
comment.storage = None
comment.alt_id = comment.uuid
comment.storage = storage
diff --git a/libbe/command/new.py b/libbe/command/new.py
index 4a0288b..6a5ac1f 100644
--- a/libbe/command/new.py
+++ b/libbe/command/new.py
@@ -126,19 +126,19 @@ class New (libbe.command.Command):
'Ambiguous bugdir {}'.format(sorted(bugdirs.values())))
storage.writeable = False
bug = bugdir.new_bug(summary=summary.strip())
- if params['creator'] != None:
+ if params['creator'] is not None:
bug.creator = params['creator']
else:
bug.creator = self._get_user_id()
- if params['reporter'] != None:
+ if params['reporter'] is not None:
bug.reporter = params['reporter']
else:
bug.reporter = bug.creator
- if params['assigned'] != None:
+ if params['assigned'] is not None:
bug.assigned = _parse_assigned(self, params['assigned'])
- if params['status'] != None:
+ if params['status'] is not None:
bug.status = params['status']
- if params['severity'] != None:
+ if params['severity'] is not None:
bug.severity = params['severity']
storage.writeable = True
bug.save()
diff --git a/libbe/command/serve_commands.py b/libbe/command/serve_commands.py
index dbdb76b..1541d12 100644
--- a/libbe/command/serve_commands.py
+++ b/libbe/command/serve_commands.py
@@ -202,7 +202,7 @@ if libbe.TESTING:
('Content-Type', 'application/octet-stream'
) in self.response_headers,
self.response_headers)
- self.assertTrue(self.exc_info == None, self.exc_info)
+ self.assertTrue(self.exc_info is None, self.exc_info)
# TODO: integration tests on ServeCommands?
unitsuite =unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
diff --git a/libbe/command/set.py b/libbe/command/set.py
index 9ec7e2c..698e657 100644
--- a/libbe/command/set.py
+++ b/libbe/command/set.py
@@ -83,7 +83,7 @@ class Set (libbe.command.Command):
else:
raise libbe.command.UserError(
'Ambiguous bugdir {}'.format(sorted(bugdirs.values())))
- if params['setting'] == None:
+ if params['setting'] is None:
keys = bugdir.settings_properties
keys.sort()
for key in keys:
@@ -94,7 +94,7 @@ class Set (libbe.command.Command):
msg += 'Allowed settings:\n '
msg += '\n '.join(bugdir.settings_properties)
raise libbe.command.UserError(msg)
- if params['value'] == None:
+ if params['value'] is None:
print(_value_string(bugdir, params['setting']))
else:
if params['value'] == 'none':
@@ -181,7 +181,7 @@ def get_bugdir_settings():
lines = dstr.split('\n')
while lines[0].startswith('This property defaults to') == False:
lines.pop(0)
- assert len(lines) != None, \
+ assert len(lines) is not None, \
'Unexpected vcs_name docstring:\n "%s"' % dstr
lines.insert(
0, 'The name of the revision control system to use.\n')
diff --git a/libbe/command/show.py b/libbe/command/show.py
index c08fd1f..2e7d59e 100644
--- a/libbe/command/show.py
+++ b/libbe/command/show.py
@@ -166,7 +166,7 @@ def _xml_footer():
return ['</be-xml>']
def output(bugdirs, ids, encoding, as_xml=True, with_comments=True):
- if ids == None or len(ids) == 0:
+ if ids is None or len(ids) == 0:
ids = []
for bugdir in list(bugdirs.values()):
bugdir.load_all_bugs()
diff --git a/libbe/command/subscribe.py b/libbe/command/subscribe.py
index 45cd0dd..b6f9cf0 100644
--- a/libbe/command/subscribe.py
+++ b/libbe/command/subscribe.py
@@ -127,17 +127,17 @@ class Subscribe (libbe.command.Command):
if params['list-all'] == True:
assert len(params['id']) == 0, params['id']
subscriber = params['subscriber']
- if subscriber == None:
+ if subscriber is None:
subscriber = self._get_user_id()
if params['unsubscribe'] == True:
- if params['servers'] == None:
+ if params['servers'] is None:
params['servers'] = 'INVALID'
- if params['types'] == None:
+ if params['types'] is None:
params['types'] = 'INVALID'
else:
- if params['servers'] == None:
+ if params['servers'] is None:
params['servers'] = '*'
- if params['types'] == None:
+ if params['types'] is None:
params['types'] = 'all'
servers = params['servers'].split(',')
types = params['types'].split(',')
@@ -247,7 +247,7 @@ def _get_subscriber(extra_strings, subscriber, type_root):
def subscribe(extra_strings, subscriber, types, servers, type_root):
args = _get_subscriber(extra_strings, subscriber, type_root)
- if args == None: # no match
+ if args is None: # no match
extra_strings.append(_generate_string(subscriber, types, servers))
return extra_strings
# Alter matched string
@@ -270,7 +270,7 @@ def subscribe(extra_strings, subscriber, types, servers, type_root):
def unsubscribe(extra_strings, subscriber, types, servers, type_root):
args = _get_subscriber(extra_strings, subscriber, type_root)
- if args == None: # no match
+ if args is None: # no match
return extra_strings # pass
# Remove matched string
i,s,ts,srvs = args
diff --git a/libbe/command/tag.py b/libbe/command/tag.py
index 51e2abe..bbffe09 100644
--- a/libbe/command/tag.py
+++ b/libbe/command/tag.py
@@ -104,9 +104,9 @@ class Tag (libbe.command.Command):
])
def _run(self, **params):
- if params['id'] == None and params['list'] == False:
+ if params['id'] is None and params['list'] == False:
raise libbe.command.UserError('Please specify a bug id.')
- if params['id'] != None and params['list'] == True:
+ if params['id'] is not None and params['list'] == True:
raise libbe.command.UserError(
'Do not specify a bug id with the --list option.')
bugdirs = self._get_bugdirs()
diff --git a/libbe/command/target.py b/libbe/command/target.py
index b13647e..eb11c11 100644
--- a/libbe/command/target.py
+++ b/libbe/command/target.py
@@ -90,10 +90,10 @@ class Target (libbe.command.Command):
def _run(self, **params):
if params['resolve'] == False:
- if params['id'] == None:
+ if params['id'] is None:
raise libbe.command.UserError('Please specify a bug id.')
else:
- if params['target'] != None:
+ if params['target'] is not None:
raise libbe.command.UserError('Too many arguments')
params['target'] = params.pop('id')
bugdirs = self._get_bugdirs()
@@ -106,7 +106,7 @@ class Target (libbe.command.Command):
raise libbe.command.UserError(
'Ambiguous bugdir {}'.format(sorted(bugdirs.values())))
bug = bug_from_target_summary(bugdirs, bugdir, params['target'])
- if bug == None:
+ if bug is None:
print('No target assigned.', file=self.stdout)
else:
print(bug.id.long_user(), file=self.stdout)
@@ -114,9 +114,9 @@ class Target (libbe.command.Command):
bugdir,bug,comment = (
libbe.command.util.bugdir_bug_comment_from_user_id(
bugdirs, params['id']))
- if params['target'] == None:
+ if params['target'] is None:
target = bug_target(bugdirs, bug)
- if target == None:
+ if target is None:
print('No target assigned.', file=self.stdout)
else:
print(target.summary, file=self.stdout)
@@ -157,8 +157,8 @@ by UUID), try
"""
def bug_from_target_summary(bugdirs, bugdir, summary=None):
- if summary == None:
- if bugdir.target == None:
+ if summary is None:
+ if bugdir.target is None:
return None
else:
return bugdir.bug_from_uuid(bugdir.target)
@@ -196,7 +196,7 @@ def remove_target(bugdirs, bug):
def add_target(bugdirs, bugdir, bug, summary):
target = bug_from_target_summary(bugdirs, bugdir, summary)
- if target == None:
+ if target is None:
target = bugdir.new_bug(summary=summary)
target.severity = 'target'
libbe.command.depend.add_block(target, bug)
diff --git a/libbe/command/util.py b/libbe/command/util.py
index 49f3490..632e22c 100644
--- a/libbe/command/util.py
+++ b/libbe/command/util.py
@@ -38,7 +38,7 @@ def complete_command(command, argument, fragment=None):
def comp_path(fragment=None):
"""List possible path completions for fragment."""
- if fragment == None:
+ if fragment is None:
fragment = '.'
comps = glob.glob(fragment+'*') + glob.glob(fragment+'/*')
if len(comps) == 1 and os.path.isdir(comps[0]):
@@ -64,14 +64,14 @@ def assignees(bugdirs):
for bugdir in list(bugdirs.values()):
bugdir.load_all_bugs()
ret.update(set([bug.assigned for bug in bugdir
- if bug.assigned != None]))
+ if bug.assigned is not None]))
return list(ret)
def complete_assigned(command, argument, fragment=None):
return assignees(command._get_bugdirs())
def complete_extra_strings(command, argument, fragment=None):
- if fragment == None:
+ if fragment is None:
return []
return [fragment]
@@ -88,7 +88,7 @@ def complete_bug_comment_id(command, argument, fragment=None,
import libbe.bugdir
import libbe.util.id
bugdirs = command._get_bugdirs()
- if fragment == None or len(fragment) == 0:
+ if fragment is None or len(fragment) == 0:
fragment = '/'
try:
p = libbe.util.id.parse_user(bugdirs, fragment)
@@ -101,7 +101,7 @@ def complete_bug_comment_id(command, argument, fragment=None,
except libbe.util.id.NoIDMatches:
return []
except libbe.util.id.MultipleIDMatches as e:
- if e.common == None:
+ if e.common is None:
# choose among bugdirs
return e.matches
common = e.common
@@ -109,7 +109,7 @@ def complete_bug_comment_id(command, argument, fragment=None,
root,residual = libbe.util.id.residual(common, fragment)
p = libbe.util.id.parse_user(bugdirs, e.common)
bug = None
- if matches == None: # fragment was complete, get a list of children uuids
+ if matches is None: # fragment was complete, get a list of children uuids
if p['type'] == 'bugdir':
bugdir = bugdirs[p['bugdir']]
matches = bugdir.uuids()
@@ -131,11 +131,11 @@ def complete_bug_comment_id(command, argument, fragment=None,
if comments == False:
return[fragment]
bugdir = bugdirs[p['bugdir']]
- if bug == None:
+ if bug is None:
bug = bugdir.bug_from_uuid(p['bug'])
child_fn = bug.comment_from_uuid
elif p['type'] == 'comment':
- assert matches == None, matches
+ assert matches is None, matches
return [fragment]
possible = []
common += '/'
@@ -180,7 +180,7 @@ def select_values(string, possible_values, name="unkown"):
['abc', 'def', 'hij']
"""
possible_values = list(possible_values) # don't alter the original
- if string == None:
+ if string is None:
pass
elif string.startswith('-'):
blacklisted_values = set(string[1:].split(','))
diff --git a/libbe/diff.py b/libbe/diff.py
index 595d512..f7ddfbe 100644
--- a/libbe/diff.py
+++ b/libbe/diff.py
@@ -256,7 +256,7 @@ class DiffTree (libbe.util.tree.Tree):
pass
else:
self.join(root, parent, data_part)
- if data_part != None:
+ if data_part is not None:
depth += 1
for child in self:
root = child.report(root, self, depth)
@@ -264,7 +264,7 @@ class DiffTree (libbe.util.tree.Tree):
def make_root(self):
return []
def join(self, root, parent, data_part):
- if data_part != None:
+ if data_part is not None:
root.append(data_part)
def data_part(self, depth, indent=True):
if self.data is None:
@@ -452,9 +452,9 @@ class Diff (object):
if BUGDIR_TYPE_ALL in bugdir_types \
or BUGDIR_TYPE_MOD in bugdir_types \
or uuid in subscribed_bugs:
- if old_bug.storage != None and old_bug.storage.is_readable():
+ if old_bug.storage is not None and old_bug.storage.is_readable():
old_bug.load_comments()
- if new_bug.storage != None and new_bug.storage.is_readable():
+ if new_bug.storage is not None and new_bug.storage.is_readable():
new_bug.load_comments()
if old_bug != new_bug:
modified.append((old_bug, new_bug))
@@ -534,7 +534,7 @@ class Diff (object):
for p in properties]
return self._attribute_changes(old, new, attributes)
def _bugdir_attribute_changes(self):
- return self._settings_properties_attribute_changes( \
+ return self._settings_properties_attribute_changes(
self.old_bugdir, self.new_bugdir)
def _bug_attribute_changes(self, old, new):
return self._settings_properties_attribute_changes(old, new)
@@ -558,8 +558,8 @@ class Diff (object):
root = self._cached_full_report
bugdir_types = [s.type for s in subscriptions if s.id == BUGDIR_ID]
subscribed_bugs = [s.id for s in subscriptions
- if BUG_TYPE_ALL.has_descendant( \
- s.type, match_self=True)]
+ if BUG_TYPE_ALL.has_descendant(
+ s.type, match_self=True)]
selected_by_bug = [node.name
for node in root.child_by_path('bugdir/bugs')]
if BUGDIR_TYPE_ALL in bugdir_types:
diff --git a/libbe/storage/base.py b/libbe/storage/base.py
index 09e176b..3ee056d 100644
--- a/libbe/storage/base.py
+++ b/libbe/storage/base.py
@@ -569,6 +569,7 @@ class VersionedStorage (Storage):
if TESTING:
+ # noinspection PyBroadException
class StorageTestCase (unittest.TestCase):
"""Test cases for Storage class."""
@@ -1131,11 +1132,11 @@ if TESTING:
storage_testcase_classes = [
c for c in (
ob for ob in list(globals().values()) if isinstance(ob, type))
- if ((issubclass(c, StorageTestCase) \
- and c.Class == Storage)
+ if ((issubclass(c, StorageTestCase)
+ and c.Class == Storage)
or
- (issubclass(c, VersionedStorageTestCase) \
- and c.Class == VersionedStorage))]
+ (issubclass(c, VersionedStorageTestCase)
+ and c.Class == VersionedStorage))]
for base_class in storage_testcase_classes:
testcase_class_name = storage_class.__name__ + base_class.__name__
diff --git a/libbe/storage/util/config.py b/libbe/storage/util/config.py
index f53f5b2..c6546a0 100644
--- a/libbe/storage/util/config.py
+++ b/libbe/storage/util/config.py
@@ -69,7 +69,7 @@ def set_val(name, value, section="DEFAULT", encoding=None):
encoding : str
The config file's encoding, defaults to :py:data:`default_encoding`.
"""
- if encoding == None:
+ if encoding is None:
encoding = default_encoding
config = configparser.ConfigParser()
if os.path.exists(path()) == False: # touch file or config
@@ -112,7 +112,7 @@ def get_val(name, section="DEFAULT", default=None, encoding=None):
True
"""
if os.path.exists(path()):
- if encoding == None:
+ if encoding is None:
encoding = default_encoding
config = configparser.ConfigParser()
f = codecs.open(path(), 'r', encoding)
diff --git a/libbe/storage/util/properties.py b/libbe/storage/util/properties.py
index 6a2b964..4489a44 100644
--- a/libbe/storage/util/properties.py
+++ b/libbe/storage/util/properties.py
@@ -42,50 +42,53 @@ import copy
import types
import libbe
+
if libbe.TESTING:
import unittest
-class ValueCheckError (ValueError):
+class ValueCheckError(ValueError):
def __init__(self, name, value, allowed):
- action = "in" # some list of allowed values
- if type(allowed) == types.FunctionType:
- action = "allowed by" # some allowed-value check function
+ action = "in" # some list of allowed values
+ if isinstance(allowed, types.FunctionType):
+ action = "allowed by" # some allowed-value check function
msg = "%s not %s %s for %s" % (value, action, allowed, name)
ValueError.__init__(self, msg)
self.name = name
self.value = value
self.allowed = allowed
+
def Property(funcs):
"""
End a chain of property decorators, returning a property.
"""
- args = {}
- args["fget"] = funcs.get("fget", None)
- args["fset"] = funcs.get("fset", None)
- args["fdel"] = funcs.get("fdel", None)
- args["doc"] = funcs.get("doc", None)
-
- #print("Creating a property with")
- #for key, val in args.items(): print(key, value)
+ args = {"fget": funcs.get("fget", None), "fset": funcs.get("fset", None), "fdel": funcs.get("fdel", None),
+ "doc": funcs.get("doc", None)}
+
+ # print("Creating a property with")
+ # for key, val in args.items(): print(key, value)
return property(**args)
+
def doc_property(doc=None):
"""
Add a docstring to a chain of property decorators.
"""
+
def decorator(funcs=None):
"""
Takes either a dict of funcs {"fget":fnX, "fset":fnY, ...}
or a function fn() returning such a dict.
"""
if hasattr(funcs, "__call__"):
- funcs = funcs() # convert from function-arg to dict
+ funcs = funcs() # convert from function-arg to dict
funcs["doc"] = doc
return funcs
+
return decorator
+
def local_property(name, null=None, mutable_null=False):
"""
Define get/set access to per-parent-instance local storage. Uses
@@ -95,11 +98,13 @@ def local_property(name, null=None, mutable_null=False):
If mutable_null == True, we only release deepcopies of the null to
the outside world.
"""
+
def decorator(funcs):
if hasattr(funcs, "__call__"):
funcs = funcs()
fget = funcs.get("fget", None)
fset = funcs.get("fset", None)
+
def _fget(self):
if fget is not None:
fget(self)
@@ -109,40 +114,49 @@ def local_property(name, null=None, mutable_null=False):
ret_null = null
value = getattr(self, "_%s_value" % name, ret_null)
return value
+
def _fset(self, value):
setattr(self, "_%s_value" % name, value)
if fset is not None:
fset(self, value)
+
funcs["fget"] = _fget
funcs["fset"] = _fset
funcs["name"] = name
return funcs
+
return decorator
+
def settings_property(name, null=None):
"""
Similar to local_property, except where local_property stores the
value in instance._<name>_value, settings_property stores the
value in instance.settings[name].
"""
+
def decorator(funcs):
if hasattr(funcs, "__call__"):
funcs = funcs()
fget = funcs.get("fget", None)
fset = funcs.get("fset", None)
+
def _fget(self):
if fget is not None:
fget(self)
value = self.settings.get(name, null)
return value
+
def _fset(self, value):
self.settings[name] = value
if fset is not None:
fset(self, value)
+
funcs["fget"] = _fget
funcs["fset"] = _fset
funcs["name"] = name
return funcs
+
return decorator
@@ -158,22 +172,30 @@ def settings_property(name, null=None):
# True
def _hash_mutable_value(value):
return repr(value)
+
+
def _init_mutable_property_cache(self):
if not hasattr(self, "_mutable_property_cache_hash"):
# first call to _fget for any mutable property
self._mutable_property_cache_hash = {}
self._mutable_property_cache_copy = {}
+
+
def _set_cached_mutable_property(self, cacher_name, property_name, value):
_init_mutable_property_cache(self)
self._mutable_property_cache_hash[(cacher_name, property_name)] = \
_hash_mutable_value(value)
self._mutable_property_cache_copy[(cacher_name, property_name)] = \
copy.deepcopy(value)
+
+
def _get_cached_mutable_property(self, cacher_name, property_name, default=None):
_init_mutable_property_cache(self)
if (cacher_name, property_name) not in self._mutable_property_cache_copy:
return default
return self._mutable_property_cache_copy[(cacher_name, property_name)]
+
+
def _eq_cached_mutable_property(self, cacher_name, property_name, value, default=None):
_init_mutable_property_cache(self)
if (cacher_name, property_name) not in self._mutable_property_cache_hash:
@@ -194,12 +216,14 @@ def defaulting_property(default=None, null=None,
null should never escape to the outside world, so don't worry
about it being a mutable.
"""
+
def decorator(funcs):
if hasattr(funcs, "__call__"):
funcs = funcs()
fget = funcs.get("fget")
fset = funcs.get("fset")
name = funcs.get("name", "<unknown>")
+
def _fget(self):
value = fget(self)
if value == null:
@@ -208,63 +232,81 @@ def defaulting_property(default=None, null=None,
else:
return default
return value
+
def _fset(self, value):
if value == default:
value = null
fset(self, value)
+
funcs["fget"] = _fget
funcs["fset"] = _fset
return funcs
+
return decorator
+
def fn_checked_property(value_allowed_fn):
"""
Define allowed values for get/set access to a property.
"""
+
def decorator(funcs):
if hasattr(funcs, "__call__"):
funcs = funcs()
fget = funcs.get("fget")
fset = funcs.get("fset")
name = funcs.get("name", "<unknown>")
+
def _fget(self):
value = fget(self)
- if value_allowed_fn(value) != True:
+ if not value_allowed_fn(value):
raise ValueCheckError(name, value, value_allowed_fn)
return value
+
def _fset(self, value):
- if value_allowed_fn(value) != True:
+ if not value_allowed_fn(value):
raise ValueCheckError(name, value, value_allowed_fn)
fset(self, value)
+
funcs["fget"] = _fget
funcs["fset"] = _fset
return funcs
+
return decorator
-def checked_property(allowed=[]):
+
+def checked_property(allowed=None):
"""
Define allowed values for get/set access to a property.
"""
+
def decorator(funcs):
if hasattr(funcs, "__call__"):
funcs = funcs()
fget = funcs.get("fget")
fset = funcs.get("fset")
name = funcs.get("name", "<unknown>")
+
def _fget(self):
value = fget(self)
if value not in allowed:
raise ValueCheckError(name, value, allowed)
return value
+
def _fset(self, value):
if value not in allowed:
raise ValueCheckError(name, value, allowed)
fset(self, value)
+
funcs["fget"] = _fget
funcs["fset"] = _fset
return funcs
+ if allowed is None:
+ allowed = []
+
return decorator
+
def cached_property(generator, initVal=None, mutable=False):
"""
Allow caching of values generated by generator(instance), where
@@ -291,11 +333,13 @@ def cached_property(generator, initVal=None, mutable=False):
generator is called whenever the cached value would otherwise be
used.
"""
+
def decorator(funcs):
if hasattr(funcs, "__call__"):
funcs = funcs()
fget = funcs.get("fget")
name = funcs.get("name", "<unknown>")
+
def _fget(self):
cache = getattr(self, "_%s_cache" % name, True)
value = fget(self)
@@ -309,10 +353,13 @@ def cached_property(generator, initVal=None, mutable=False):
else:
value = generator(self)
return value
+
funcs["fget"] = _fget
return funcs
+
return decorator
+
def primed_property(primer, initVal=None, unprimeableVal=None):
"""
Just like a cached_property, except that instead of returning a
@@ -326,14 +373,17 @@ def primed_property(primer, initVal=None, unprimeableVal=None):
whenever ._<name>_prime is True, or is False or missing and
value == initVal.
"""
+
def decorator(funcs):
if hasattr(funcs, "__call__"):
funcs = funcs()
fget = funcs.get("fget")
name = funcs.get("name", "<unknown>")
+
def _fget(self):
prime = getattr(self, "_%s_prime" % name, False)
- if prime == False:
+ value = None
+ if not prime:
value = fget(self)
if prime == True or (prime == False and value == initVal):
primer(self)
@@ -341,10 +391,13 @@ def primed_property(primer, initVal=None, unprimeableVal=None):
if prime == False and value == initVal:
return unprimeableVal
return value
+
funcs["fget"] = _fget
return funcs
+
return decorator
+
def change_hook_property(hook, mutable=False, default=None):
"""Call the function `hook` whenever a value different from the
current value is set.
@@ -373,40 +426,46 @@ def change_hook_property(hook, mutable=False, default=None):
`hook(instance, old_value, new_value)`, where `instance` is a
reference to the class instance to which this property belongs.
"""
+
def decorator(funcs):
if hasattr(funcs, "__call__"):
funcs = funcs()
fget = funcs.get("fget")
fset = funcs.get("fset")
name = funcs.get("name", "<unknown>")
- def _fget(self, new_value=None, from_fset=False): # only used if mutable == True
+
+ def _fget(self, new_value=None, from_fset=False): # only used if mutable == True
if from_fset:
- value = new_value # compare new value with cached
+ value = new_value # compare new value with cached
else:
- value = fget(self) # compare current value with cached
+ value = fget(self) # compare current value with cached
if _eq_cached_mutable_property(self, "change hook property", name, value, default) != 0:
# there has been a change, cache new value
old_value = _get_cached_mutable_property(self, "change hook property", name, default)
_set_cached_mutable_property(self, "change hook property", name, value)
- if from_fset: # return previously cached value
+ if from_fset: # return previously cached value
value = old_value
- else: # the value changed while we weren't looking
+ else: # the value changed while we weren't looking
hook(self, old_value, value)
return value
+
def _fset(self, value):
- if mutable: # get cached previous value
+ if mutable: # get cached previous value
old_value = _fget(self, new_value=value, from_fset=True)
else:
old_value = fget(self)
fset(self, value)
if value != old_value:
hook(self, old_value, value)
+
if mutable:
funcs["fget"] = _fget
funcs["fset"] = _fset
return funcs
+
return decorator
+
if libbe.TESTING:
class DecoratorTests(unittest.TestCase):
def testLocalDoc(self):
@@ -415,40 +474,48 @@ if libbe.TESTING:
@doc_property("A fancy property")
def x():
return {}
+
self.assertTrue(Test.x.__doc__ == "A fancy property",
Test.x.__doc__)
+
def testLocalProperty(self):
class Test(object):
@Property
@local_property(name="LOCAL")
def x():
return {}
+
t = Test()
- self.assertTrue(t.x == None, str(t.x))
- t.x = 'z' # the first set initializes ._LOCAL_value
+ self.assertTrue(t.x is None, str(t.x))
+ t.x = 'z' # the first set initializes ._LOCAL_value
self.assertTrue(t.x == 'z', str(t.x))
self.assertTrue("_LOCAL_value" in dir(t), dir(t))
self.assertTrue(t._LOCAL_value == 'z', t._LOCAL_value)
+
def testSettingsProperty(self):
class Test(object):
@Property
@settings_property(name="attr")
def x():
return {}
+
def __init__(self):
self.settings = {}
+
t = Test()
- self.assertTrue(t.x == None, str(t.x))
- t.x = 'z' # the first set initializes ._LOCAL_value
+ self.assertTrue(t.x is None, str(t.x))
+ t.x = 'z' # the first set initializes ._LOCAL_value
self.assertTrue(t.x == 'z', str(t.x))
self.assertTrue("attr" in t.settings, t.settings)
self.assertTrue(t.settings["attr"] == 'z', t.settings["attr"])
+
def testDefaultingLocalProperty(self):
class Test(object):
@Property
@defaulting_property(default='y', null='x')
@local_property(name="DEFAULT", null=5)
def x(): return {}
+
t = Test()
self.assertTrue(t.x == 5, str(t.x))
t.x = 'x'
@@ -459,14 +526,17 @@ if libbe.TESTING:
self.assertTrue(t.x == 'z', str(t.x))
t.x = 5
self.assertTrue(t.x == 5, str(t.x))
+
def testCheckedLocalProperty(self):
class Test(object):
@Property
@checked_property(allowed=['x', 'y', 'z'])
@local_property(name="CHECKED")
def x(): return {}
+
def __init__(self):
self._CHECKED_value = 'x'
+
t = Test()
self.assertTrue(t.x == 'x', str(t.x))
try:
@@ -475,6 +545,7 @@ if libbe.TESTING:
except ValueCheckError as e:
pass
self.assertTrue(type(e) == ValueCheckError, type(e))
+
def testTwoCheckedLocalProperties(self):
class Test(object):
@Property
@@ -486,9 +557,11 @@ if libbe.TESTING:
@checked_property(allowed=['a', 'b', 'c'])
@local_property(name="A")
def a(): return {}
+
def __init__(self):
self._A_value = 'a'
self._X_value = 'x'
+
t = Test()
try:
t.x = 'a'
@@ -508,14 +581,17 @@ if libbe.TESTING:
t.a = 'a'
t.a = 'b'
t.a = 'c'
+
def testFnCheckedLocalProperty(self):
class Test(object):
@Property
- @fn_checked_property(lambda v : v in ['x', 'y', 'z'])
+ @fn_checked_property(lambda v: v in ['x', 'y', 'z'])
@local_property(name="CHECKED")
def x(): return {}
+
def __init__(self):
self._CHECKED_value = 'x'
+
t = Test()
self.assertTrue(t.x == 'x', str(t.x))
try:
@@ -524,57 +600,65 @@ if libbe.TESTING:
except ValueCheckError as e:
pass
self.assertTrue(type(e) == ValueCheckError, type(e))
+
def testCachedLocalProperty(self):
class Gen(object):
def __init__(self):
self.i = 0
+
def __call__(self, owner):
self.i += 1
return self.i
+
class Test(object):
@Property
@cached_property(generator=Gen(), initVal=None)
@local_property(name="CACHED")
def x(): return {}
+
t = Test()
self.assertFalse("_CACHED_cache" in dir(t),
- getattr(t, "_CACHED_cache", None))
+ getattr(t, "_CACHED_cache", None))
self.assertTrue(t.x == 1, t.x)
self.assertTrue(t.x == 1, t.x)
self.assertTrue(t.x == 1, t.x)
t.x = 8
self.assertTrue(t.x == 8, t.x)
self.assertTrue(t.x == 8, t.x)
- t._CACHED_cache = False # Caching is off, but the stored value
- val = t.x # is 8, not the initVal (None), so we
- self.assertTrue(val == 8, val) # get 8.
- t._CACHED_value = None # Now we've set the stored value to None
- val = t.x # so future calls to fget (like this)
- self.assertTrue(val == 2, val) # will call the generator every time...
+ t._CACHED_cache = False # Caching is off, but the stored value
+ val = t.x # is 8, not the initVal (None), so we
+ self.assertTrue(val == 8, val) # get 8.
+ t._CACHED_value = None # Now we've set the stored value to None
+ val = t.x # so future calls to fget (like this)
+ self.assertTrue(val == 2, val) # will call the generator every time...
val = t.x
self.assertTrue(val == 3, val)
val = t.x
self.assertTrue(val == 4, val)
- t._CACHED_cache = True # We turn caching back on, and get
- self.assertTrue(t.x == 1, str(t.x)) # the original cached value.
- del t._CACHED_cached_value # Removing that value forces a
- self.assertTrue(t.x == 5, str(t.x)) # single cache-regenerating call
- self.assertTrue(t.x == 5, str(t.x)) # to the genenerator, after which
- self.assertTrue(t.x == 5, str(t.x)) # we get the new cached value.
+ t._CACHED_cache = True # We turn caching back on, and get
+ self.assertTrue(t.x == 1, str(t.x)) # the original cached value.
+ del t._CACHED_cached_value # Removing that value forces a
+ self.assertTrue(t.x == 5, str(t.x)) # single cache-regenerating call
+ self.assertTrue(t.x == 5, str(t.x)) # to the genenerator, after which
+ self.assertTrue(t.x == 5, str(t.x)) # we get the new cached value.
+
def testPrimedLocalProperty(self):
class Test(object):
def prime(self):
self.settings["PRIMED"] = self.primeVal
+
@Property
@primed_property(primer=prime, initVal=None, unprimeableVal=2)
@settings_property(name="PRIMED")
def x(): return {}
+
def __init__(self):
- self.settings={}
+ self.settings = {}
self.primeVal = "initialized"
+
t = Test()
self.assertFalse("_PRIMED_prime" in dir(t),
- getattr(t, "_PRIMED_prime", None))
+ getattr(t, "_PRIMED_prime", None))
self.assertTrue(t.x == "initialized", t.x)
t.x = 1
self.assertTrue(t.x == 1, t.x)
@@ -590,6 +674,7 @@ if libbe.TESTING:
t.x = None
t.primeVal = None
self.assertTrue(t.x == 2, t.x)
+
def testChangeHookLocalProperty(self):
class Test(object):
def _hook(self, old, new):
@@ -600,16 +685,18 @@ if libbe.TESTING:
@change_hook_property(_hook)
@local_property(name="HOOKED")
def x(): return {}
+
t = Test()
t.x = 1
- self.assertTrue(t.old == None, t.old)
+ self.assertTrue(t.old is None, t.old)
self.assertTrue(t.new == 1, t.new)
t.x = 1
- self.assertTrue(t.old == None, t.old)
+ self.assertTrue(t.old is None, t.old)
self.assertTrue(t.new == 1, t.new)
t.x = 2
self.assertTrue(t.old == 1, t.old)
self.assertTrue(t.new == 2, t.new)
+
def testChangeHookMutableProperty(self):
class Test(object):
def _hook(self, old, new):
@@ -621,10 +708,11 @@ if libbe.TESTING:
@change_hook_property(_hook, mutable=True)
@local_property(name="HOOKED")
def x(): return {}
+
t = Test()
t.hook_calls = 0
t.x = []
- self.assertTrue(t.old == None, t.old)
+ self.assertTrue(t.old is None, t.old)
self.assertTrue(t.new == [], t.new)
self.assertTrue(t.hook_calls == 1, t.hook_calls)
a = t.x
@@ -650,19 +738,20 @@ if libbe.TESTING:
self.assertTrue(t.old == [], t.old)
self.assertTrue(t.new == [5], t.new)
self.assertTrue(t.hook_calls == 4, t.hook_calls)
- t.x.append(6) # this append(6) is not noticed yet
+ t.x.append(6) # this append(6) is not noticed yet
self.assertTrue(t.old == [], t.old)
- self.assertTrue(t.new == [5,6], t.new)
+ self.assertTrue(t.new == [5, 6], t.new)
self.assertTrue(t.hook_calls == 4, t.hook_calls)
# this append(7) is not noticed, but the t.x get causes the
# append(6) to be noticed
t.x.append(7)
self.assertTrue(t.old == [5], t.old)
- self.assertTrue(t.new == [5,6,7], t.new)
+ self.assertTrue(t.new == [5, 6, 7], t.new)
self.assertTrue(t.hook_calls == 5, t.hook_calls)
- a = t.x # now the append(7) is noticed
- self.assertTrue(t.old == [5,6], t.old)
- self.assertTrue(t.new == [5,6,7], t.new)
+ a = t.x # now the append(7) is noticed
+ self.assertTrue(t.old == [5, 6], t.old)
+ self.assertTrue(t.new == [5, 6, 7], t.new)
self.assertTrue(t.hook_calls == 6, t.hook_calls)
+
suite = unittest.TestLoader().loadTestsFromTestCase(DecoratorTests)
diff --git a/libbe/storage/util/settings_object.py b/libbe/storage/util/settings_object.py
index d872f49..8981e35 100644
--- a/libbe/storage/util/settings_object.py
+++ b/libbe/storage/util/settings_object.py
@@ -57,7 +57,7 @@ class EMPTY (_Token):
def prop_save_settings(self, old, new):
"""The default action undertaken when a property changes.
"""
- if self.storage != None and self.storage.is_writeable():
+ if self.storage is not None and self.storage.is_writeable():
self.save_settings()
def prop_load_settings(self):
@@ -68,7 +68,7 @@ def prop_load_settings(self):
`._setup_saved_settings()` internally. If `.storage` is
inaccessible, don't do anything.
"""
- if self.storage != None and self.storage.is_readable():
+ if self.storage is not None and self.storage.is_readable():
self.load_settings()
# Some name-mangling routines for pretty printing setting names
@@ -160,18 +160,18 @@ def versioned_property(name, doc,
required_saved_properties.append(name)
def decorator(funcs):
fulldoc = doc
- if default != None or generator == None:
+ if default is not None or generator is None:
defaulting = defaulting_property(default=default, null=EMPTY,
mutable_default=mutable)
fulldoc += "\n\nThis property defaults to %s." % default
- if generator != None:
+ if generator is not None:
cached = cached_property(generator=generator, initVal=EMPTY,
mutable=mutable)
fulldoc += "\n\nThis property is generated with %s." % generator
- if check_fn != None:
+ if check_fn is not None:
fn_checked = fn_checked_property(value_allowed_fn=check_fn)
fulldoc += "\n\nThis property is checked with %s." % check_fn
- if allowed != None:
+ if allowed is not None:
checked = checked_property(allowed=allowed)
fulldoc += "\n\nThe allowed values for this property are: %s." \
% (', '.join(allowed))
@@ -182,13 +182,13 @@ def versioned_property(name, doc,
settings = settings_property(name=name, null=UNPRIMED)
docp = doc_property(doc=fulldoc)
deco = hooked(primed(settings(docp(funcs))))
- if default != None or generator == None:
+ if default is not None or generator is None:
deco = defaulting(deco)
- if generator != None:
+ if generator is not None:
deco = cached(deco)
- if check_fn != None:
+ if check_fn is not None:
deco = fn_checked(deco)
- if allowed != None:
+ if allowed is not None:
deco = checked(deco)
return Property(deco)
return decorator
@@ -233,7 +233,7 @@ class SavedSettingsObject(object):
Sets up a settings dict loaded from storage. Fills in
all missing settings entries with EMPTY.
"""
- if settings == None:
+ if settings is None:
settings = {}
for property in self.settings_properties:
if property not in self.settings \
@@ -274,7 +274,7 @@ class SavedSettingsObject(object):
def clear_cached_setting(self, setting=None):
"If setting=None, clear *all* cached settings"
- if setting != None:
+ if setting is not None:
if hasattr(self, "_%s_cached_value" % setting):
delattr(self, "_%s_cached_value" % setting)
else:
@@ -342,20 +342,20 @@ if libbe.TESTING == True:
# accessing t.content_type triggers the priming, but
# t.storage.is_readable() == False, so nothing happens.
t.storage.readable = False
- self.assertTrue(t.content_type == None, t.content_type)
+ self.assertTrue(t.content_type is None, t.content_type)
self.assertTrue(t.settings == {}, t.settings)
self.assertTrue(len(t.settings) == 0, len(t.settings))
- self.assertTrue(t.content_type == None, t.content_type)
+ self.assertTrue(t.content_type is None, t.content_type)
# accessing t.content_type triggers the priming again, and
# now that t.storage.is_readable() == True, this fills out
# t.settings with EMPTY data. At this point there should
# be one load and no saves.
t.storage.readable = True
- self.assertTrue(t.content_type == None, t.content_type)
+ self.assertTrue(t.content_type is None, t.content_type)
self.assertTrue(len(t.settings) == 1, len(t.settings))
self.assertTrue(t.settings["Content-type"] == EMPTY,
t.settings["Content-type"])
- self.assertTrue(t.content_type == None, t.content_type)
+ self.assertTrue(t.content_type is None, t.content_type)
self.assertTrue(t.load_count == 1, t.load_count)
self.assertTrue(len(t.storage) == 0, len(t.storage))
# an explicit call to load settings forces a reload,
@@ -364,7 +364,7 @@ if libbe.TESTING == True:
self.assertTrue(len(t.settings) == 1, len(t.settings))
self.assertTrue(t.settings["Content-type"] == EMPTY,
t.settings["Content-type"])
- self.assertTrue(t.content_type == None, t.content_type)
+ self.assertTrue(t.content_type is None, t.content_type)
self.assertTrue(t.load_count == 2, t.load_count)
self.assertTrue(len(t.storage) == 0, len(t.storage))
# now we set a value
@@ -400,7 +400,7 @@ if libbe.TESTING == True:
t.content_type = EMPTY
self.assertTrue(t.settings["Content-type"] == EMPTY,
t.settings["Content-type"])
- self.assertTrue(t.content_type == None, t.content_type)
+ self.assertTrue(t.content_type is None, t.content_type)
self.assertTrue(len(t.settings) == 1, len(t.settings))
self.assertTrue(t.settings["Content-type"] == EMPTY,
t.settings["Content-type"])
@@ -592,7 +592,7 @@ if libbe.TESTING == True:
def list_type(): return {}
t = Test()
self.assertTrue(len(t.storage) == 0, len(t.storage))
- self.assertTrue(t.list_type == None, t.list_type)
+ self.assertTrue(t.list_type is None, t.list_type)
self.assertTrue(len(t.storage) == 0, len(t.storage))
self.assertTrue(t.settings["List-type"]==EMPTY,
t.settings["List-type"])
@@ -614,6 +614,6 @@ if libbe.TESTING == True:
{'List-type':[5]}],
t.storage)
- unitsuite = unittest.TestLoader().loadTestsFromTestCase( \
+ unitsuite = unittest.TestLoader().loadTestsFromTestCase(
SavedSettingsObjectTests)
suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()])
diff --git a/libbe/storage/util/upgrade.py b/libbe/storage/util/upgrade.py
index 12d177a..6b278f1 100644
--- a/libbe/storage/util/upgrade.py
+++ b/libbe/storage/util/upgrade.py
@@ -117,7 +117,7 @@ class Upgrader (object):
self.repo = repo
vcs_name = self._get_vcs_name()
- if vcs_name == None:
+ if vcs_name is None:
vcs_name = 'None'
self.vcs = libbe.storage.vcs.vcs_by_name(vcs_name)
self.vcs.repo = self.repo
diff --git a/libbe/storage/vcs/base.py b/libbe/storage/vcs/base.py
index 0521e90..813905c 100644
--- a/libbe/storage/vcs/base.py
+++ b/libbe/storage/vcs/base.py
@@ -430,7 +430,7 @@ class VCS (libbe.storage.base.VersionedStorage):
Get the file contents as they were in a given revision.
Revision==None specifies the current revision.
"""
- if revision != None:
+ if revision is not None:
raise libbe.storage.base.InvalidRevision(
'The %s VCS does not support revision specifiers' % self.name)
path = os.path.join(self.repo, path)
@@ -553,7 +553,7 @@ class VCS (libbe.storage.base.VersionedStorage):
-1
"""
if not hasattr(self, '_parsed_version') \
- or self._parsed_version == None:
+ or self._parsed_version is None:
num_part = self.version().split(' ')[0]
self._parsed_version = []
for num in num_part.split('.'):
@@ -598,7 +598,7 @@ class VCS (libbe.storage.base.VersionedStorage):
return -1
def installed(self):
- if self.version() != None:
+ if self.version() is not None:
return True
return False
@@ -769,7 +769,7 @@ class VCS (libbe.storage.base.VersionedStorage):
self._cached_path_id.remove_id(id)
def _ancestors(self, id=None, revision=None):
- if id==None:
+ if id is None:
path = self.be_dir
else:
path = self.path(id, revision, relpath=False)
@@ -794,7 +794,7 @@ class VCS (libbe.storage.base.VersionedStorage):
self._u_rel_path(path), revision)
listdir = lambda path : self._vcs_listdir(
self._u_rel_path(path), revision)
- if id==None:
+ if id is None:
path = self.be_dir
else:
path = self.path(id, revision, relpath=False)
@@ -813,7 +813,7 @@ class VCS (libbe.storage.base.VersionedStorage):
if c is None: continue
cpath = os.path.join(path, c)
children[i] = self._u_path_to_id(cpath)
- return [c for c in children if c != None]
+ return [c for c in children if c is not None]
def _get(self, id, default=libbe.util.InvalidObject, revision=None):
try:
@@ -1017,7 +1017,7 @@ class VCS (libbe.storage.base.VersionedStorage):
'/a.b/c/.be'
"""
if root is None:
- assert self.repo != None, "VCS not rooted"
+ assert self.repo is not None, "VCS not rooted"
root = self.repo
return os.path.abspath(os.path.join(root, path))
@@ -1138,7 +1138,7 @@ if libbe.TESTING:
dp = os.path.realpath(self.dirname)
vcs_name = self.Class.name
self.assertTrue(
- dp == rp or rp == None,
+ dp == rp or rp is None,
"%(vcs_name)s VCS root in wrong dir (%(dp)s %(rp)s)" % vars())
class VCS_get_user_id_TestCase(VCSTestCase):
@@ -1151,7 +1151,7 @@ if libbe.TESTING:
if user_id is None:
return
name,email = libbe.ui.util.user.parse_user_id(user_id)
- if email != None:
+ if email is not None:
self.assertTrue('@' in email, email)
def make_vcs_testcase_subclasses(vcs_class, namespace):
diff --git a/libbe/storage/vcs/bzr.py b/libbe/storage/vcs/bzr.py
index 6da299a..fa5b879 100644
--- a/libbe/storage/vcs/bzr.py
+++ b/libbe/storage/vcs/bzr.py
@@ -64,7 +64,7 @@ class Bzr(base.VCS):
self.versioned = True
def _vcs_version(self):
- if bzrlib == None:
+ if bzrlib is None:
return None
return bzrlib.__version__
@@ -77,7 +77,7 @@ class Bzr(base.VCS):
return c.username()
def _vcs_detect(self, path):
- if self._u_search_parent_directories(path, '.bzr') != None :
+ if self._u_search_parent_directories(path, '.bzr') is not None:
return True
return False
@@ -135,7 +135,7 @@ class Bzr(base.VCS):
pass
def _parse_revision_string(self, revision=None):
- if revision == None:
+ if revision is None:
return revision
rev_opt = bzrlib.option.Option.OPTIONS['revision']
try:
@@ -145,7 +145,7 @@ class Bzr(base.VCS):
return rev_spec
def _vcs_get_file_contents(self, path, revision=None):
- if revision == None:
+ if revision is None:
return base.VCS._vcs_get_file_contents(self, path, revision)
path = os.path.join(self.repo, path)
revision = self._parse_revision_string(revision)
diff --git a/libbe/storage/vcs/darcs.py b/libbe/storage/vcs/darcs.py
index 12eabf4..07ddb9e 100644
--- a/libbe/storage/vcs/darcs.py
+++ b/libbe/storage/vcs/darcs.py
@@ -178,7 +178,7 @@ class Darcs(base.VCS):
if revision is None:
return base.VCS._vcs_get_file_contents(self, path, revision)
if self.version_cmp(2, 0, 0) == 1:
- status,output,error = self._u_invoke_client( \
+ status,output,error = self._u_invoke_client(
'show', 'contents', '--patch', revision, path)
return output
# Darcs versions < 2.0.0pre2 lack the 'show contents' command
@@ -209,7 +209,7 @@ class Darcs(base.VCS):
if self.version_cmp(2, 3, 1) == 1:
# Sun Nov 15 20:32:06 EST 2009 thomashartman1@gmail.com
# * add versioned show files functionality (darcs show files -p 'some patch')
- status,output,error = self._u_invoke_client( \
+ status,output,error = self._u_invoke_client(
'show', 'files', '--no-files', '--patch', revision)
children = output.rstrip('\n').splitlines()
rpath = '.'
@@ -227,7 +227,7 @@ class Darcs(base.VCS):
# Wed Dec 9 05:42:21 EST 2009 Luca Molteni <volothamp@gmail.com>
# * resolve issue835 show file with file directory arguments
path = path.rstrip(os.path.sep)
- status,output,error = self._u_invoke_client( \
+ status,output,error = self._u_invoke_client(
'show', 'files', '--patch', revision, path)
files = output.rstrip('\n').splitlines()
if path == '.':
@@ -243,7 +243,7 @@ class Darcs(base.VCS):
def _vcs_commit(self, commitfile, allow_empty=False):
id = self.get_user_id()
- if id == None or '@' not in id:
+ if id is None or '@' not in id:
id = '%s <%s@invalid.com>' % (id, id)
args = ['record', '--all', '--author', id, '--logfile', commitfile]
status,output,error = self._u_invoke_client(*args)
diff --git a/libbe/storage/vcs/git.py b/libbe/storage/vcs/git.py
index 9a15c92..d8a966d 100644
--- a/libbe/storage/vcs/git.py
+++ b/libbe/storage/vcs/git.py
@@ -191,7 +191,7 @@ class PygitGit(base.VCS):
return eobj
def _vcs_get_file_contents(self, path, revision=None):
- if revision == None:
+ if revision is None:
return base.VCS._vcs_get_file_contents(self, path, revision)
else:
blob = self._git_get_object(path=path, revision=revision)
@@ -311,7 +311,7 @@ class ExecGit (PygitGit):
return None # Git has no infomation
def _vcs_detect(self, path):
- if self._u_search_parent_directories(path, '.git') != None :
+ if self._u_search_parent_directories(path, '.git') is not None:
return True
return False
@@ -339,7 +339,7 @@ class ExecGit (PygitGit):
if not os.path.isdir(self._u_abspath(path)):
self._u_invoke_client('rm', '-f', path)
def _vcs_get_file_contents(self, path, revision=None):
- if revision == None:
+ if revision is None:
return base.VCS._vcs_get_file_contents(self, path, revision)
else:
arg = '%s:%s' % (revision,path)
diff --git a/libbe/storage/vcs/hg.py b/libbe/storage/vcs/hg.py
index 0ebdfb0..6198bc8 100644
--- a/libbe/storage/vcs/hg.py
+++ b/libbe/storage/vcs/hg.py
@@ -74,7 +74,7 @@ class Hg(base.VCS):
self.__updated = [] # work around http://mercurial.selenic.com/bts/issue618
def _vcs_version(self):
- if version == None:
+ if version is None:
return None
return version()
@@ -106,7 +106,7 @@ class Hg(base.VCS):
def _vcs_detect(self, path):
"""Detect whether a directory is revision-controlled using Mercurial"""
- if self._u_search_parent_directories(path, '.hg') != None:
+ if self._u_search_parent_directories(path, '.hg') is not None:
return True
return False
@@ -131,7 +131,7 @@ class Hg(base.VCS):
self.__updated.append(path) # work around http://mercurial.selenic.com/bts/issue618
def _vcs_get_file_contents(self, path, revision=None):
- if revision == None:
+ if revision is None:
return base.VCS._vcs_get_file_contents(self, path, revision)
else:
return self._u_invoke_client('cat', '-r', revision, path)
diff --git a/libbe/storage/vcs/monotone.py b/libbe/storage/vcs/monotone.py
index 1d74c5b..4eaced8 100644
--- a/libbe/storage/vcs/monotone.py
+++ b/libbe/storage/vcs/monotone.py
@@ -86,7 +86,7 @@ class Monotone (base.VCS):
-1
"""
if not hasattr(self, '_parsed_version') \
- or self._parsed_version == None:
+ or self._parsed_version is None:
self._parsed_version = [int(x) for x in self.version().split('.')]
for current,other in zip(self._parsed_version, args):
c = cmp(current,other)
@@ -129,7 +129,7 @@ class Monotone (base.VCS):
return None # Monotone has no infomation
def _vcs_detect(self, path):
- if self._u_search_parent_directories(path, '_MTN') != None :
+ if self._u_search_parent_directories(path, '_MTN') is not None:
return True
return False
@@ -153,11 +153,11 @@ class Monotone (base.VCS):
"""Invoke the client on our branch.
"""
arglist = []
- if self._db_path != None:
+ if self._db_path is not None:
arglist.extend(['--db', self._db_path])
- if self._key != None:
+ if self._key is not None:
arglist.extend(['--key', self._key])
- if self._key_dir != None:
+ if self._key_dir is not None:
arglist.extend(['--keydir', self._key_dir])
arglist.extend(args)
args = tuple(arglist)
diff --git a/libbe/ui/command_line.py b/libbe/ui/command_line.py
index b649e24..3b8089f 100644
--- a/libbe/ui/command_line.py
+++ b/libbe/ui/command_line.py
@@ -59,13 +59,13 @@ class CmdOptionParser(optparse.OptionParser):
option.validate()
self._option_by_name[option.name] = option
long_opt = '--%s' % option.name
- if option.short_name != None:
+ if option.short_name is not None:
short_opt = '-%s' % option.short_name
assert '_' not in option.name, \
'Non-reconstructable option name %s' % option.name
kwargs = {'dest':option.name.replace('-', '_'),
'help':option.help}
- if option.arg == None: # a callback option
+ if option.arg is None: # a callback option
kwargs['action'] = 'callback'
kwargs['callback'] = self.callback
elif option.arg.type == 'bool':
@@ -77,7 +77,7 @@ class CmdOptionParser(optparse.OptionParser):
kwargs['action'] = 'store'
kwargs['metavar'] = option.arg.metavar
kwargs['default'] = option.arg.default
- if option.short_name != None:
+ if option.short_name is not None:
opt = optparse.Option(short_opt, long_opt, **kwargs)
else:
opt = optparse.Option(long_opt, **kwargs)
@@ -95,7 +95,7 @@ class CmdOptionParser(optparse.OptionParser):
for name,value in list(options.items()):
argument = None
option = self._option_by_name[name]
- if option.arg != None:
+ if option.arg is not None:
argument = option.arg
if value == '--complete':
fragment = None
@@ -108,7 +108,7 @@ class CmdOptionParser(optparse.OptionParser):
name = args[i-1][2:]
if name == option.name:
break
- elif option.short_name != None \
+ elif option.short_name is not None \
and args[i-1].startswith('-') \
and args[i-1].endswith(option.short_name):
break
@@ -163,7 +163,7 @@ class CmdOptionParser(optparse.OptionParser):
def complete(self, argument=None, fragment=None):
comps = self.command.complete(argument, fragment)
- if fragment != None:
+ if fragment is not None:
comps = [c for c in comps if c.startswith(fragment)]
if len(comps) > 0:
print('\n'.join(comps), file=self.command.stdout)
@@ -258,7 +258,7 @@ class BE (libbe.command.Command):
cmdlist = []
for name in libbe.command.commands():
Class = libbe.command.get_command_class(command_name=name)
- assert hasattr(Class, '__doc__') and Class.__doc__ != None, \
+ assert hasattr(Class, '__doc__') and Class.__doc__ is not None, \
'Command class %s missing docstring' % Class
cmdlist.append((Class.name, Class.__doc__.splitlines()[0]))
cmdlist.sort()
diff --git a/libbe/ui/util/editor.py b/libbe/ui/util/editor.py
index 8412ff6..5ab519f 100644
--- a/libbe/ui/util/editor.py
+++ b/libbe/ui/util/editor.py
@@ -64,14 +64,14 @@ def editor_string(comment=None, encoding=None):
>>> del os.environ["EDITOR"]
>>> del os.environ["VISUAL"]
"""
- if encoding == None:
+ if encoding is None:
encoding = libbe.util.encoding.get_text_file_encoding()
editor = None
for name in ('VISUAL', 'EDITOR'):
if name in os.environ and os.environ[name] != '':
editor = os.environ[name]
break
- if editor == None:
+ if editor is None:
raise CantFindEditor()
fhandle, fname = tempfile.mkstemp()
try:
diff --git a/libbe/ui/util/user.py b/libbe/ui/util/user.py
index 4a4e7f1..1d7e874 100644
--- a/libbe/ui/util/user.py
+++ b/libbe/ui/util/user.py
@@ -92,7 +92,7 @@ def create_user_id(name, email=None):
parse_user_id : inverse
"""
assert len(name) > 0
- if email == None or len(email) == 0:
+ if email is None or len(email) == 0:
return name
else:
return formataddr((name, email))
@@ -137,11 +137,11 @@ def get_user_id(storage=None):
configured it directly.
"""
user = libbe.storage.util.config.get_val('user')
- if user != None:
+ if user is not None:
return user
- if storage != None and hasattr(storage, 'get_user_id'):
+ if storage is not None and hasattr(storage, 'get_user_id'):
user = storage.get_user_id()
- if user != None:
+ if user is not None:
return user
name = get_fallback_fullname()
email = get_fallback_email()
diff --git a/libbe/util/encoding.py b/libbe/util/encoding.py
index c5e242b..8a3b53e 100644
--- a/libbe/util/encoding.py
+++ b/libbe/util/encoding.py
@@ -45,18 +45,18 @@ def get_encoding():
Guess a useful input/output/filesystem encoding... Maybe we need
seperate encodings for input/output and filesystem? Hmm...
"""
- if ENCODING != None:
+ if ENCODING is not None:
return ENCODING
encoding = locale.getpreferredencoding() or sys.getdefaultencoding()
return encoding
def get_input_encoding():
- if INPUT_ENCODING != None:
+ if INPUT_ENCODING is not None:
return INPUT_ENCODING
return sys.__stdin__.encoding or get_encoding()
def get_output_encoding():
- if OUTPUT_ENCODING != None:
+ if OUTPUT_ENCODING is not None:
return OUTPUT_ENCODING
return sys.__stdout__.encoding or get_encoding()
@@ -83,7 +83,7 @@ def known_encoding(encoding):
def get_file_contents(path, mode='r', encoding=None, decode=False):
if decode == True:
- if encoding == None:
+ if encoding is None:
encoding = get_text_file_encoding()
f = codecs.open(path, mode, encoding)
else:
@@ -94,7 +94,7 @@ def get_file_contents(path, mode='r', encoding=None, decode=False):
def set_file_contents(path, contents, mode='w', encoding=None):
if type(contents) == str:
- if encoding == None:
+ if encoding is None:
encoding = get_text_file_encoding()
f = codecs.open(path, mode, encoding)
else:
diff --git a/libbe/util/id.py b/libbe/util/id.py
index 078dd3f..f4d19ae 100644
--- a/libbe/util/id.py
+++ b/libbe/util/id.py
@@ -156,7 +156,7 @@ class NoIDMatches (KeyError):
self.possible_ids = possible_ids
self.msg = msg
def __str__(self):
- if self.msg == None:
+ if self.msg is None:
return 'No id matches %s.\n%s' % (self.id, self.possible_ids)
return self.msg
@@ -175,7 +175,7 @@ class InvalidIDStructure (KeyError):
self.id = id
self.msg = msg
def __str__(self):
- if self.msg == None:
+ if self.msg is None:
return 'Invalid id structure "%s"' % self.id
return self.msg
@@ -188,7 +188,7 @@ def _assemble(args, check_length=False):
"""
args = list(args)
for i,arg in enumerate(args):
- if arg == None:
+ if arg is None:
args[i] = ''
id = '/'.join(args)
if check_length == True:
@@ -271,7 +271,7 @@ def _expand(truncated_id, common, other_ids):
other_ids = list(other_ids)
if len(other_ids) == 0:
raise NoIDMatches(truncated_id, other_ids)
- if truncated_id == None:
+ if truncated_id is None:
if len(other_ids) == 1:
return other_ids[0]
raise MultipleIDMatches(truncated_id, common, other_ids)
@@ -377,7 +377,7 @@ class ID (object):
def user(self):
ids = []
for o in self._ancestors():
- if o == None:
+ if o is None:
ids.append(None)
else:
ids.append(_truncate(o.uuid, o.sibling_uuids()))
@@ -480,7 +480,7 @@ class IDreplacer (object):
def __call__(self, match):
ids = []
for m in match.groups():
- if m == None:
+ if m is None:
m = ''
ids.append(m)
try:
@@ -577,7 +577,7 @@ def _parse_user(id):
ret = {}
args = _split(id, check_length=True)
for i,(type,arg) in enumerate(zip(HIERARCHY, args)):
- if arg != None and len(arg) == 0:
+ if arg is not None and len(arg) == 0:
raise InvalidIDStructure(
id, 'Invalid %s part %d "%s" of id "%s"' % (type, i, arg, id))
ret['type'] = type
@@ -609,7 +609,7 @@ if libbe.TESTING == True:
def __init__(self, uuid, parent=None, siblings=[]):
self.uuid = uuid
self._siblings = siblings
- if parent == None:
+ if parent is None:
type_i = 0
else:
assert parent.type in HIERARCHY, parent
diff --git a/libbe/util/subproc.py b/libbe/util/subproc.py
index 5412b08..912433f 100644
--- a/libbe/util/subproc.py
+++ b/libbe/util/subproc.py
@@ -54,7 +54,7 @@ def invoke(args, stdin=None, stdout=PIPE, stderr=PIPE, expect=(0,),
unicode_output == True, convert stdout and stdin strings to
unicode before returing them.
"""
- if cwd == None:
+ if cwd is None:
cwd = '.'
if isinstance(shell, (str,)):
list_args = ' '.split(args) # sloppy, but just for logging
@@ -81,11 +81,11 @@ def invoke(args, stdin=None, stdout=PIPE, stderr=PIPE, expect=(0,),
stdout,stderr = q.communicate(input=stdin)
status = q.wait()
if unicode_output == True:
- if encoding == None:
+ if encoding is None:
encoding = get_encoding()
- if stdout != None:
+ if stdout is not None:
stdout = str(stdout, encoding)
- if stderr != None:
+ if stderr is not None:
stderr = str(stderr, encoding)
libbe.LOG.debug('{0}\n{1}{2}'.format(status, stdout, stderr))
else:
diff --git a/libbe/util/wsgi.py b/libbe/util/wsgi.py
index cfa43be..9f22596 100644
--- a/libbe/util/wsgi.py
+++ b/libbe/util/wsgi.py
@@ -46,7 +46,7 @@ try:
import cherrypy.wsgiserver
except ImportError:
cherrypy = None
-if cherrypy != None:
+if cherrypy is not None:
try: # CherryPy >= 3.2
import cherrypy.wsgiserver.ssl_builtin
except ImportError: # CherryPy <= 3.1.X
@@ -239,9 +239,9 @@ class WSGI_Object (object):
req_uri += '?' + environ['QUERY_STRING']
start = time.localtime()
if time.daylight:
- offset = time.altzone / 60 / 60 * -100
+ offset = time.altzone // 60 // 60 * -100
else:
- offset = time.timezone / 60 / 60 * -100
+ offset = time.timezone // 60 // 60 * -100
if offset >= 0:
offset = '+{:04d}'.format(offset)
elif offset < 0:
@@ -800,7 +800,7 @@ if libbe.TESTING:
('Content-Type','text/plain'),
('X-Dummy-Header','Dummy Value')],
self.caller.response_headers)
- self.assertTrue(self.caller.exc_info == None, self.caller.exc_info)
+ self.assertTrue(self.caller.exc_info is None, self.caller.exc_info)
def test_log_request(self):
self.app.log_request(
diff --git a/misc/xml/be-mail-to-xml b/misc/xml/be-mail-to-xml
index 6155baa..6071c74 100755
--- a/misc/xml/be-mail-to-xml
+++ b/misc/xml/be-mail-to-xml
@@ -27,19 +27,21 @@ followed by a blank line.
import base64
import email.utils
-from libbe.util.encoding import get_output_encoding
-from libbe.util.utility import time_to_str
-import mailbox # the mailbox people really want an on-disk copy
+import mailbox # the mailbox people really want an on-disk copy
import optparse
-from time import asctime, gmtime, mktime
import types
+from time import mktime
from xml.sax.saxutils import escape
-BREAK = u'--' # signature separator
+from libbe.util.encoding import get_output_encoding
+from libbe.util.utility import time_to_str
+
+BREAK = u'--' # signature separator
DEFAULT_ENCODING = get_output_encoding()
KNOWN_IDS = []
+
def normalize_email_address(address):
"""
Standardize whitespace, etc.
@@ -49,6 +51,7 @@ def normalize_email_address(address):
return None
return addr
+
def normalize_RFC_2822_date(date):
"""
Some email clients write non-RFC 2822-compliant date tags like:
@@ -57,60 +60,59 @@ def normalize_RFC_2822_date(date):
to deal with such inconsistencies.
"""
time_tuple = email.utils.parsedate(date)
- assert time_tuple != None, \
+ assert time_tuple is not None, \
'unparsable date: "%s"' % date
return time_to_str(mktime(time_tuple))
+
def strip_footer(body):
body_lines = body.splitlines()
- for i,line in enumerate(body_lines):
+ for i, line in enumerate(body_lines):
if line.startswith(BREAK):
break
- i += 1 # increment past the current valid line.
+ i += 1 # increment past the current valid line.
return u'\n'.join(body_lines[:i]).strip()
+
def comment_message_to_xml(message, fields=None):
- if fields == None:
+ if fields is None:
fields = {}
- new_fields = {}
- new_fields[u'alt-id'] = message[u'message-id']
- new_fields[u'in-reply-to'] = message[u'in-reply-to']
- new_fields[u'author'] = normalize_email_address(message[u'from'])
- new_fields[u'date'] = message[u'date']
- if new_fields[u'date'] != None:
+ new_fields = {u'alt-id': message[u'message-id'], u'in-reply-to': message[u'in-reply-to'],
+ u'author': normalize_email_address(message[u'from']), u'date': message[u'date']}
+ if new_fields[u'date'] is not None:
new_fields[u'date'] = normalize_RFC_2822_date(new_fields[u'date'])
new_fields[u'content-type'] = message.get_content_type()
- for k,v in new_fields.items():
- if v != None and type(v) != types.UnicodeType:
- fields[k] = unicode(v, encoding=DEFAULT_ENCODING)
- elif v == None and k in fields:
+ for k, v in new_fields.items():
+ if v is not None and type(v) != types.UnicodeType:
+ fields[k] = str(v, encoding=DEFAULT_ENCODING)
+ elif v is None and k in fields:
new_fields[k] = fields[k]
- for k,v in fields.items():
+ for k, v in fields.items():
if k not in new_fields:
new_fields.k = fields[k]
fields = new_fields
- if fields[u'in-reply-to'] == None:
- if message[u'references'] != None:
+ if fields[u'in-reply-to'] is None:
+ if message[u'references'] is not None:
refs = message[u'references'].split()
- for ref in refs: # search for a known reference id.
+ for ref in refs: # search for a known reference id.
if ref in KNOWN_IDS:
fields[u'in-reply-to'] = ref
break
- if fields[u'in-reply-to'] == None and len(refs) > 0:
- fields[u'in-reply-to'] = refs[0] # default to the first
- else: # check for mutliple in-reply-to references.
+ if fields[u'in-reply-to'] is None and len(refs) > 0:
+ fields[u'in-reply-to'] = refs[0] # default to the first
+ else: # check for mutliple in-reply-to references.
refs = fields[u'in-reply-to'].split()
found_ref = False
- for ref in refs: # search for a known reference id.
+ for ref in refs: # search for a known reference id.
if ref in KNOWN_IDS:
fields[u'in-reply-to'] = ref
found_ref = True
break
if found_ref == False and len(refs) > 0:
- fields[u'in-reply-to'] = refs[0] # default to the first
+ fields[u'in-reply-to'] = refs[0] # default to the first
- if fields[u'alt-id'] != None:
+ if fields[u'alt-id'] is not None:
KNOWN_IDS.append(fields[u'alt-id'])
if message.is_multipart():
@@ -123,51 +125,56 @@ def comment_message_to_xml(message, fields=None):
continue
fields[u'author'] = from_str
fields[u'date'] = date
- if len(ret) > 0: # we've added one part already
- fields.pop(u'alt-id') # don't pass alt-id to other parts
- fields[u'in-reply-to'] = alt_id # others respond to first
+ if len(ret) > 0: # we've added one part already
+ fields.pop(u'alt-id') # don't pass alt-id to other parts
+ fields[u'in-reply-to'] = alt_id # others respond to first
ret.append(comment_message_to_xml(m, fields))
return u'\n'.join(ret)
charset = message.get_content_charset(DEFAULT_ENCODING).lower()
- #assert charset == DEFAULT_ENCODING.lower(), \
+ # assert charset == DEFAULT_ENCODING.lower(), \
# u"Unknown charset: %s" % charset
- if message[u'content-transfer-encoding'] == None:
+ if message[u'content-transfer-encoding'] is None:
encoding = DEFAULT_ENCODING
else:
encoding = message[u'content-transfer-encoding'].lower()
- body = message.get_payload(decode=True) # attempt to decode
- assert body != None, "Unable to decode?"
+ body = message.get_payload(decode=True) # attempt to decode
+ assert body is not None, "Unable to decode?"
if fields[u'content-type'].startswith(u"text/"):
- body = strip_footer(unicode(body, encoding=charset))
+ body = strip_footer(str(body, encoding=charset))
else:
- body = base64.encode(body)
+ body = base64.encodebytes(body)
fields[u'body'] = body
lines = [u"<comment>"]
- for tag,body in fields.items():
- if body != None:
+ for tag, body in fields.items():
+ if body is not None:
ebody = escape(body)
lines.append(u" <%s>%s</%s>" % (tag, ebody, tag))
lines.append(u"</comment>")
return u'\n'.join(lines)
+
def main(argv):
parser = optparse.OptionParser(usage='%prog [options] mailbox')
formats = ['mbox', 'Maildir', 'MH', 'Babyl', 'MMDF']
parser.add_option('-f', '--format', type='choice', dest='format',
help="Select the mailbox format from %s. See the mailbox module's documention for descriptions of these formats." \
- % ', '.join(formats),
+ % ', '.join(formats),
default='mbox', choices=formats)
- options,args = parser.parse_args(argv)
+ options, args = parser.parse_args(argv)
mailbox_file = args[1]
reader = getattr(mailbox, options.format)
mb = reader(mailbox_file, factory=None)
- print u'<?xml version="1.0" encoding="%s" ?>' % DEFAULT_ENCODING
- print u"<be-xml>"
+ print
+ u'<?xml version="1.0" encoding="%s" ?>' % DEFAULT_ENCODING
+ print
+ u"<be-xml>"
for message in mb:
- print comment_message_to_xml(message)
- print u"</be-xml>"
+ print
+ comment_message_to_xml(message)
+ print
+ u"</be-xml>"
if __name__ == "__main__":
diff --git a/misc/xml/be-xml-to-mbox b/misc/xml/be-xml-to-mbox
index 0151792..48454f9 100755
--- a/misc/xml/be-xml-to-mbox
+++ b/misc/xml/be-xml-to-mbox
@@ -27,23 +27,20 @@ Messages begin with a a From_ line, followed by RFC 822 email,
followed by a blank line.
"""
-#from mailbox import mbox, Message # the mailbox people really want an on-disk copy
+# from mailbox import mbox, Message # the mailbox people really want an on-disk copy
import email.utils
from libbe.util.encoding import get_output_encoding
from libbe.util.utility import str_to_time as rfc2822_to_gmtime_integer
from time import asctime, gmtime
import types
-try: # import core module, Python >= 2.5
- from xml.etree import ElementTree
-except ImportError: # look for non-core module
- from elementtree import ElementTree
+from xml.etree import ElementTree
from xml.sax.saxutils import unescape
-
DEFAULT_DOMAIN = "invalid.com"
DEFAULT_EMAIL = "dummy@" + DEFAULT_DOMAIN
DEFAULT_ENCODING = get_output_encoding()
+
def rfc2822_to_asctime(rfc2822_string):
"""Convert an RFC 2822-fomatted string into a asctime string.
>>> rfc2822_to_asctime("Thu, 01 Jan 1970 00:00:00 +0000")
@@ -53,27 +50,32 @@ def rfc2822_to_asctime(rfc2822_string):
return asctime(gmtime(0))
return asctime(gmtime(rfc2822_to_gmtime_integer(rfc2822_string)))
-class LimitedAttrDict (dict):
+
+class LimitedAttrDict(dict):
"""
Dict with error checking, to avoid invalid bug/comment fields.
"""
- _attrs = [] # override with list of valid attribute names
+ _attrs = [] # override with list of valid attribute names
+
def __init__(self, **kwargs):
dict.__init__(self)
- for key,value in kwargs.items():
+ for key, value in kwargs.items():
self[key] = value
+
def __setitem__(self, key, item):
self._validate_key(key)
dict.__setitem__(self, key, item)
+
def _validate_key(self, key):
if key in self._attrs:
return
elif type(key) not in types.StringTypes:
- raise TypeError, "Invalid attribute type %s for '%s'" % (type(key), key)
+ raise TypeError("Invalid attribute type %s for '%s'" % (type(key), key))
else:
- raise ValueError, "Invalid attribute name '%s'" % key
+ raise ValueError("Invalid attribute name '%s'" % key)
+
-class Bug (LimitedAttrDict):
+class Bug(LimitedAttrDict):
_attrs = [u"uuid",
u"short-name",
u"severity",
@@ -85,32 +87,34 @@ class Bug (LimitedAttrDict):
u"summary",
u"comments",
u"extra-strings"]
+
def print_to_mbox(self):
if "creator" in self:
# otherwise, probably a `be show` uuid-only bug to avoid
# root comments.
- name,addr = email.utils.parseaddr(self["creator"])
- print "From %s %s" % (addr, rfc2822_to_asctime(self["created"]))
- print "Message-id: <%s@%s>" % (self["uuid"], DEFAULT_DOMAIN)
- print "Date: %s" % self["created"]
- print "From: %s" % self["creator"]
- print "Content-Type: %s; charset=%s" \
- % ("text/plain", DEFAULT_ENCODING)
- print "Content-Transfer-Encoding: 8bit"
- print "Subject: %s: %s" % (self["short-name"], self["summary"])
+ name, addr = email.utils.parseaddr(self["creator"])
+ print("From %s %s" % (addr, rfc2822_to_asctime(self["created"])))
+ print("Message-id: <%s@%s>" % (self["uuid"], DEFAULT_DOMAIN))
+ print("Date: %s" % self["created"])
+ print("From: %s" % self["creator"])
+ print("Content-Type: %s; charset=%s"
+ % ("text/plain", DEFAULT_ENCODING))
+ print("Content-Transfer-Encoding: 8bit")
+ print("Subject: %s: %s" % (self["short-name"], self["summary"]))
if "extra-strings" in self:
for estr in self["extra-strings"]:
- print "X-Extra-String: %s" % estr
- print ""
- print self["summary"]
- print ""
+ print("X-Extra-String: %s" % estr)
+ print()
+ print(self["summary"])
+ print()
if "comments" in self:
for comment in self["comments"]:
- comment.print_to_mbox(self)
+ comment.print_to_mbox(self)
+
def init_from_etree(self, element):
assert element.tag == "bug", element.tag
for field in element.getchildren():
- text = unescape(unicode(field.text).decode("unicode_escape").strip())
+ text = unescape(bytes(field.text).decode("unicode_escape").strip())
if field.tag == "comment":
comm = Comment()
comm.init_from_etree(field)
@@ -126,12 +130,14 @@ class Bug (LimitedAttrDict):
else:
self[field.tag] = text
+
def wrap_id(id):
if "@" not in id:
return "<%s@%s>" % (id, DEFAULT_DOMAIN)
return id
-class Comment (LimitedAttrDict):
+
+class Comment(LimitedAttrDict):
_attrs = [u"uuid",
u"alt-id",
u"short-name",
@@ -141,49 +147,54 @@ class Comment (LimitedAttrDict):
u"content-type",
u"body",
u"extra-strings"]
+
def print_to_mbox(self, bug=None):
- if bug == None:
+ if bug is None:
bug = Bug()
bug[u"uuid"] = u"no-uuid"
- name,addr = email.utils.parseaddr(self["author"])
- print "From %s %s" % (addr, rfc2822_to_asctime(self["date"]))
- if "uuid" in self: id = self["uuid"]
- elif "alt-id" in self: id = self["alt-id"]
- else: id = None
- if id != None:
- print "Message-id: %s" % wrap_id(id)
+ name, addr = email.utils.parseaddr(self["author"])
+ print("From %s %s" % (addr, rfc2822_to_asctime(self["date"])))
+ if "uuid" in self:
+ id = self["uuid"]
+ elif "alt-id" in self:
+ id = self["alt-id"]
+ else:
+ id = None
+ if id is not None:
+ print("Message-id: %s" % wrap_id(id))
if "alt-id" in self:
- print "Alt-id: %s" % wrap_id(self["alt-id"])
- print "Date: %s" % self["date"]
- print "From: %s" % self["author"]
+ print("Alt-id: %s" % wrap_id(self["alt-id"]))
+ print("Date: %s" % self["date"])
+ print("From: %s" % self["author"])
subject = ""
if "short-name" in self:
- subject += self["short-name"]+u": "
+ subject += self["short-name"] + u": "
if "summary" in bug:
subject += bug["summary"]
else:
subject += u"no-subject"
- print "Subject: %s" % subject
+ print("Subject: %s" % subject)
if "in-reply-to" not in self.keys():
self["in-reply-to"] = bug["uuid"]
- print "In-Reply-To: %s" % wrap_id(self["in-reply-to"])
+ print("In-Reply-To: %s" % wrap_id(self["in-reply-to"]))
if "extra-strings" in self:
for estr in self["extra-strings"]:
- print "X-Extra-String: %s" % estr
+ print("X-Extra-String: %s" % estr)
if self["content-type"].startswith("text/"):
- print "Content-Transfer-Encoding: 8bit"
- print "Content-Type: %s; charset=%s" \
- % (self["content-type"], DEFAULT_ENCODING)
+ print("Content-Transfer-Encoding: 8bit")
+ print("Content-Type: %s; charset=%s"
+ % (self["content-type"], DEFAULT_ENCODING))
else:
- print "Content-Transfer-Encoding: base64"
- print "Content-Type: %s;" % (self["content-type"])
- print ""
- print self["body"]
- print ""
+ print("Content-Transfer-Encoding: base64")
+ print("Content-Type: %s;" % (self["content-type"]))
+ print()
+ print(self["body"])
+ print()
+
def init_from_etree(self, element):
assert element.tag == "comment", element.tag
for field in element.getchildren():
- text = unescape(unicode(field.text).decode("unicode_escape").strip())
+ text = unescape(bytes(field.text).decode("unicode_escape").strip())
if field.tag == "extra-string":
if "extra-strings" in self:
self["extra-strings"].append(text)
@@ -191,9 +202,10 @@ class Comment (LimitedAttrDict):
self["extra-strings"] = [text]
else:
if field.tag == "body":
- text+="\n"
+ text += "\n"
self[field.tag] = text
+
def print_to_mbox(element):
if element.tag == "bug":
b = Bug()
@@ -207,14 +219,15 @@ def print_to_mbox(element):
for elt in element.getchildren():
print_to_mbox(elt)
+
if __name__ == "__main__":
import codecs
import sys
-
+
sys.stdin = codecs.getreader(DEFAULT_ENCODING)(sys.stdin)
sys.stdout = codecs.getwriter(DEFAULT_ENCODING)(sys.stdout)
- if len(sys.argv) == 1: # no filename given, use stdin
+ if len(sys.argv) == 1: # no filename given, use stdin
xml_unicode = sys.stdin.read()
else:
xml_unicode = codecs.open(sys.argv[1], "r", DEFAULT_ENCODING).read()
diff --git a/test.py b/test.py
index 0604528..ffc0130 100644
--- a/test.py
+++ b/test.py
@@ -52,7 +52,7 @@ def python_tree(root_path='libbe', root_modname='libbe'):
stack.append(c)
else:
continue
- if f.parent == None:
+ if f.parent is None:
f.modname = root_modname
else:
f.modname = f.parent.modname + '.' + f.name
diff --git a/update-copyright b/update-copyright
-Subproject cd7751d74780f3c73d843b46bff1182eae36411
+Subproject e7724a0017849f130444e7dfc396c875809e306