Remove AttrDict and enable pylint typecheck message category.
The AttrDict class had Python 2 leftovers which the linter flagged and isn't really necessary anyway, plus it wasn't licensed under the GPL.
This commit is contained in:
parent
9ec4dbd088
commit
370685f6b3
5 changed files with 52 additions and 205 deletions
|
@ -26,7 +26,7 @@ extension-pkg-allow-list=
|
||||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||||
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
|
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
|
||||||
# for backward compatibility.)
|
# for backward compatibility.)
|
||||||
extension-pkg-whitelist=
|
extension-pkg-whitelist=seccomp
|
||||||
|
|
||||||
# Return non-zero exit code if any of these messages/categories are detected,
|
# Return non-zero exit code if any of these messages/categories are detected,
|
||||||
# even if score is above --fail-under value. Syntax same as enable. Messages
|
# even if score is above --fail-under value. Syntax same as enable. Messages
|
||||||
|
@ -156,6 +156,7 @@ enable=F, # Fatal
|
||||||
spelling,
|
spelling,
|
||||||
string,
|
string,
|
||||||
nonascii-checker,
|
nonascii-checker,
|
||||||
|
typecheck,
|
||||||
# Specific import checks:
|
# Specific import checks:
|
||||||
wildcard-import,
|
wildcard-import,
|
||||||
# Specific refactoring checks:
|
# Specific refactoring checks:
|
||||||
|
|
23
convo.py
23
convo.py
|
@ -14,7 +14,6 @@ except ImportError:
|
||||||
from dataobjs import PesterHistory
|
from dataobjs import PesterHistory
|
||||||
from parsetools import convertTags, lexMessage, mecmd, colorBegin, colorEnd, smiledict
|
from parsetools import convertTags, lexMessage, mecmd, colorBegin, colorEnd, smiledict
|
||||||
import parsetools
|
import parsetools
|
||||||
from pnc.dep.attrdict import AttrDict
|
|
||||||
|
|
||||||
PchumLog = logging.getLogger("pchumLogger")
|
PchumLog = logging.getLogger("pchumLogger")
|
||||||
|
|
||||||
|
@ -33,33 +32,33 @@ class PesterTabWindow(QtWidgets.QFrame):
|
||||||
self.tabs.tabCloseRequested[int].connect(self.tabClose)
|
self.tabs.tabCloseRequested[int].connect(self.tabClose)
|
||||||
self.tabs.tabMoved[int, int].connect(self.tabMoved)
|
self.tabs.tabMoved[int, int].connect(self.tabMoved)
|
||||||
|
|
||||||
self.shortcuts = AttrDict()
|
self.shortcuts = {}
|
||||||
self.shortcuts.tabNext = QShortcut(
|
self.shortcuts["tabNext"] = QShortcut(
|
||||||
QtGui.QKeySequence("Ctrl+j"),
|
QtGui.QKeySequence("Ctrl+j"),
|
||||||
self,
|
self,
|
||||||
context=QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut,
|
context=QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut,
|
||||||
)
|
)
|
||||||
self.shortcuts.tabLast = QShortcut(
|
self.shortcuts["tabLast"] = QShortcut(
|
||||||
QtGui.QKeySequence("Ctrl+k"),
|
QtGui.QKeySequence("Ctrl+k"),
|
||||||
self,
|
self,
|
||||||
context=QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut,
|
context=QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut,
|
||||||
)
|
)
|
||||||
# Note that we use reversed keys here.
|
# Note that we use reversed keys here.
|
||||||
self.shortcuts.tabUp = QShortcut(
|
self.shortcuts["tabUp"] = QShortcut(
|
||||||
QtGui.QKeySequence("Ctrl+PgDown"),
|
QtGui.QKeySequence("Ctrl+PgDown"),
|
||||||
self,
|
self,
|
||||||
context=QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut,
|
context=QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut,
|
||||||
)
|
)
|
||||||
self.shortcuts.tabDn = QShortcut(
|
self.shortcuts["tabDn"] = QShortcut(
|
||||||
QtGui.QKeySequence("Ctrl+PgUp"),
|
QtGui.QKeySequence("Ctrl+PgUp"),
|
||||||
self,
|
self,
|
||||||
context=QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut,
|
context=QtCore.Qt.ShortcutContext.WidgetWithChildrenShortcut,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.shortcuts.tabNext.activated.connect(self.nudgeTabNext)
|
self.shortcuts["tabNext"].activated.connect(self.nudgeTabNext)
|
||||||
self.shortcuts.tabUp.activated.connect(self.nudgeTabNext)
|
self.shortcuts["tabUp"].activated.connect(self.nudgeTabNext)
|
||||||
self.shortcuts.tabLast.activated.connect(self.nudgeTabLast)
|
self.shortcuts["tabLast"].activated.connect(self.nudgeTabLast)
|
||||||
self.shortcuts.tabDn.activated.connect(self.nudgeTabLast)
|
self.shortcuts["tabDn"].activated.connect(self.nudgeTabLast)
|
||||||
|
|
||||||
self.initTheme(self.mainwindow.theme)
|
self.initTheme(self.mainwindow.theme)
|
||||||
self.layout = QtWidgets.QVBoxLayout()
|
self.layout = QtWidgets.QVBoxLayout()
|
||||||
|
@ -544,7 +543,7 @@ class PesterText(QtWidgets.QTextEdit):
|
||||||
window.chatlog.log(parent.chum.handle, lexmsg)
|
window.chatlog.log(parent.chum.handle, lexmsg)
|
||||||
else:
|
else:
|
||||||
if (
|
if (
|
||||||
(window.idler.auto or window.idler.manual)
|
(window.idler["auto"] or window.idler["manual"])
|
||||||
and parent.chumopen
|
and parent.chumopen
|
||||||
and not parent.isBot(chum.handle)
|
and not parent.isBot(chum.handle)
|
||||||
):
|
):
|
||||||
|
@ -675,7 +674,7 @@ class PesterInput(QtWidgets.QLineEdit):
|
||||||
self.setText(prev)
|
self.setText(prev)
|
||||||
elif event.key() in [QtCore.Qt.Key.Key_PageUp, QtCore.Qt.Key.Key_PageDown]:
|
elif event.key() in [QtCore.Qt.Key.Key_PageUp, QtCore.Qt.Key.Key_PageDown]:
|
||||||
self.parent().textArea.keyPressEvent(event)
|
self.parent().textArea.keyPressEvent(event)
|
||||||
self.parent().mainwindow.idler.time = 0
|
self.parent().mainwindow.idler["time"] = 0
|
||||||
super().keyPressEvent(event)
|
super().keyPressEvent(event)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ if ostools.isLinux():
|
||||||
import libseccomp
|
import libseccomp
|
||||||
|
|
||||||
# import console
|
# import console
|
||||||
from pnc.dep.attrdict import AttrDict
|
|
||||||
from user_profile import (
|
from user_profile import (
|
||||||
userConfig,
|
userConfig,
|
||||||
userProfile,
|
userProfile,
|
||||||
|
@ -162,8 +161,8 @@ BOTNAMES.extend(SERVICES)
|
||||||
# Save the main app. From here, we should be able to get everything else in
|
# Save the main app. From here, we should be able to get everything else in
|
||||||
# order, for console use.
|
# order, for console use.
|
||||||
_CONSOLE = False
|
_CONSOLE = False
|
||||||
_CONSOLE_ENV = AttrDict()
|
_CONSOLE_ENV = {}
|
||||||
_CONSOLE_ENV.PAPP = None
|
_CONSOLE_ENV["PAPP"] = None
|
||||||
# Python 3
|
# Python 3
|
||||||
QString = str
|
QString = str
|
||||||
# Command line arguments
|
# Command line arguments
|
||||||
|
@ -1313,7 +1312,7 @@ class PesterWindow(MovingWindow):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
# For debugging
|
# For debugging
|
||||||
_CONSOLE_ENV.PAPP = self
|
_CONSOLE_ENV["PAPP"] = self
|
||||||
# TODO: karxi: SO! At the end of this function it seems like that
|
# TODO: karxi: SO! At the end of this function it seems like that
|
||||||
# object is just made into None or.../something/. Somehow, it just
|
# object is just made into None or.../something/. Somehow, it just
|
||||||
# DIES, and I haven't the slightest idea why. I've tried multiple ways
|
# DIES, and I haven't the slightest idea why. I've tried multiple ways
|
||||||
|
@ -1332,7 +1331,7 @@ class PesterWindow(MovingWindow):
|
||||||
self.memos = CaseInsensitiveDict()
|
self.memos = CaseInsensitiveDict()
|
||||||
self.tabconvo = None
|
self.tabconvo = None
|
||||||
self.tabmemo = None
|
self.tabmemo = None
|
||||||
self.shortcuts = AttrDict()
|
self.shortcuts = {}
|
||||||
|
|
||||||
self.setAutoFillBackground(False)
|
self.setAutoFillBackground(False)
|
||||||
self.setObjectName("main")
|
self.setObjectName("main")
|
||||||
|
@ -1637,26 +1636,24 @@ class PesterWindow(MovingWindow):
|
||||||
|
|
||||||
self.waitingMessages = waitingMessageHolder(self)
|
self.waitingMessages = waitingMessageHolder(self)
|
||||||
|
|
||||||
self.idler = AttrDict(
|
self.idler = {
|
||||||
dict(
|
# autoidle
|
||||||
# autoidle
|
"auto": False,
|
||||||
auto=False,
|
# setidle
|
||||||
# setidle
|
"manual": False,
|
||||||
manual=False,
|
# idlethreshold
|
||||||
# idlethreshold
|
"threshold": 60 * self.config.idleTime(),
|
||||||
threshold=60 * self.config.idleTime(),
|
# idleaction
|
||||||
# idleaction
|
"action": self.idleaction,
|
||||||
action=self.idleaction,
|
# idletimer
|
||||||
# idletimer
|
"timer": QtCore.QTimer(self),
|
||||||
timer=QtCore.QTimer(self),
|
# idleposition
|
||||||
# idleposition
|
"pos": QtGui.QCursor.pos(),
|
||||||
pos=QtGui.QCursor.pos(),
|
# idletime
|
||||||
# idletime
|
"time": 0,
|
||||||
time=0,
|
}
|
||||||
)
|
self.idler["timer"].timeout.connect(self.checkIdle)
|
||||||
)
|
self.idler["timer"].start(1000)
|
||||||
self.idler.timer.timeout.connect(self.checkIdle)
|
|
||||||
self.idler.timer.start(1000)
|
|
||||||
|
|
||||||
if not self.config.defaultprofile():
|
if not self.config.defaultprofile():
|
||||||
self.changeProfile()
|
self.changeProfile()
|
||||||
|
@ -2912,49 +2909,49 @@ class PesterWindow(MovingWindow):
|
||||||
def toggleIdle(self, idle):
|
def toggleIdle(self, idle):
|
||||||
if idle:
|
if idle:
|
||||||
# We checked the box to go idle.
|
# We checked the box to go idle.
|
||||||
self.idler.manual = True
|
self.idler["manual"] = True
|
||||||
self.setAway.emit(True)
|
self.setAway.emit(True)
|
||||||
self.randhandler.setIdle(True)
|
self.randhandler.setIdle(True)
|
||||||
self._sendIdleMsgs()
|
self._sendIdleMsgs()
|
||||||
else:
|
else:
|
||||||
self.idler.manual = False
|
self.idler["manual"] = False
|
||||||
self.setAway.emit(False)
|
self.setAway.emit(False)
|
||||||
self.randhandler.setIdle(False)
|
self.randhandler.setIdle(False)
|
||||||
self.idler.time = 0
|
self.idler["time"] = 0
|
||||||
|
|
||||||
# karxi: TODO: Need to consider sticking an idle-setter here.
|
# karxi: TODO: Need to consider sticking an idle-setter here.
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def checkIdle(self):
|
def checkIdle(self):
|
||||||
newpos = QtGui.QCursor.pos()
|
newpos = QtGui.QCursor.pos()
|
||||||
oldpos = self.idler.pos
|
oldpos = self.idler["pos"]
|
||||||
# Save the new position.
|
# Save the new position.
|
||||||
self.idler.pos = newpos
|
self.idler["pos"] = newpos
|
||||||
|
|
||||||
if self.idler.manual:
|
if self.idler["manual"]:
|
||||||
# We're already idle, because the user said to be.
|
# We're already idle, because the user said to be.
|
||||||
self.idler.time = 0
|
self.idler["time"] = 0
|
||||||
return
|
return
|
||||||
elif self.idler.auto:
|
elif self.idler["auto"]:
|
||||||
self.idler.time = 0
|
self.idler["time"] = 0
|
||||||
if newpos != oldpos:
|
if newpos != oldpos:
|
||||||
# Cursor moved; unset idle.
|
# Cursor moved; unset idle.
|
||||||
self.idler.auto = False
|
self.idler["auto"] = False
|
||||||
self.setAway.emit(False)
|
self.setAway.emit(False)
|
||||||
self.randhandler.setIdle(False)
|
self.randhandler.setIdle(False)
|
||||||
return
|
return
|
||||||
|
|
||||||
if newpos != oldpos:
|
if newpos != oldpos:
|
||||||
# Our cursor has moved, which means we can't be idle.
|
# Our cursor has moved, which means we can't be idle.
|
||||||
self.idler.time = 0
|
self.idler["time"] = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
# If we got here, WE ARE NOT IDLE, but may become so
|
# If we got here, WE ARE NOT IDLE, but may become so
|
||||||
self.idler.time += 1
|
self.idler["time"] += 1
|
||||||
if self.idler.time >= self.idler.threshold:
|
if self.idler["time"] >= self.idler["threshold"]:
|
||||||
# We've been idle for long enough to fall automatically idle.
|
# We've been idle for long enough to fall automatically idle.
|
||||||
self.idler.auto = True
|
self.idler["auto"] = True
|
||||||
# We don't need this anymore.
|
# We don't need this anymore.
|
||||||
self.idler.time = 0
|
self.idler["time"] = 0
|
||||||
# Make it clear that we're idle.
|
# Make it clear that we're idle.
|
||||||
self.setAway.emit(True)
|
self.setAway.emit(True)
|
||||||
self.randhandler.setIdle(True)
|
self.randhandler.setIdle(True)
|
||||||
|
@ -3369,7 +3366,7 @@ class PesterWindow(MovingWindow):
|
||||||
curidle = self.config.idleTime()
|
curidle = self.config.idleTime()
|
||||||
if idlesetting != curidle:
|
if idlesetting != curidle:
|
||||||
self.config.set("idleTime", idlesetting)
|
self.config.set("idleTime", idlesetting)
|
||||||
self.idler.threshold = 60 * idlesetting
|
self.idler["threshold"] = 60 * idlesetting
|
||||||
# theme
|
# theme
|
||||||
ghostchumsetting = self.optionmenu.ghostchum.isChecked()
|
ghostchumsetting = self.optionmenu.ghostchum.isChecked()
|
||||||
curghostchum = self.config.ghostchum()
|
curghostchum = self.config.ghostchum()
|
||||||
|
|
|
@ -1,146 +0,0 @@
|
||||||
# Heavily modified version of the code featured at the given link
|
|
||||||
## {{{ http://code.activestate.com/recipes/473786/ (r1)
|
|
||||||
class AttrDict(dict):
|
|
||||||
"""A dictionary with attribute-style access. It maps attribute access to
|
|
||||||
the real dictionary.
|
|
||||||
|
|
||||||
Note that accesses to preexisting (e.g. class inherited) or reserved
|
|
||||||
attributes are handled as they would be normally, and will not be
|
|
||||||
overwritten.
|
|
||||||
Overload _is_reserved if you want to change this."""
|
|
||||||
|
|
||||||
def __init__(self, init={}):
|
|
||||||
super().__init__(init)
|
|
||||||
|
|
||||||
def __getstate__(self):
|
|
||||||
return list(self.__dict__.items())
|
|
||||||
|
|
||||||
def __setstate__(self, items):
|
|
||||||
for key, val in items:
|
|
||||||
self.__dict__[key] = val
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"{type(self).__name__}({super().__repr__()})"
|
|
||||||
|
|
||||||
def __setitem__(self, name, value):
|
|
||||||
return super().__setitem__(name, value)
|
|
||||||
|
|
||||||
def __getitem__(self, name):
|
|
||||||
return super().__getitem__(name)
|
|
||||||
|
|
||||||
def __delitem__(self, name):
|
|
||||||
return super().__delitem__(name)
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
# NOTE: __getattr__ is called if the code has already failed to access
|
|
||||||
# an attribute on this object. The rest of this code reflects this.
|
|
||||||
# We could override __getattribute__ to bypass this, but that's not
|
|
||||||
# worthwhile.
|
|
||||||
|
|
||||||
# We don't do any special handling for reserved names.
|
|
||||||
if self._is_reserved(name):
|
|
||||||
# Fall back to normal handling, by force.
|
|
||||||
return object.__getattribute__(self, name)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Try to __getitem__.
|
|
||||||
result = self[name]
|
|
||||||
except (KeyError, AttributeError):
|
|
||||||
# Raising KeyError here will confuse __deepcopy__, so don't do
|
|
||||||
# that.
|
|
||||||
# Throw a custom error.
|
|
||||||
raise AttributeError(f"No key/attr {name!r}")
|
|
||||||
return result
|
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
|
||||||
# Set to the attribute first if it's defined.
|
|
||||||
# (NOTE: This isn't subject to the same checking as __getattr__.)
|
|
||||||
# Using dir() also checks non-instance definitions, so things defined
|
|
||||||
# on a class can be easily set on an instance this way.
|
|
||||||
|
|
||||||
# Detect special/reserved names.
|
|
||||||
if name in dir(self) or self._is_reserved(name):
|
|
||||||
# Set it if it's 'special' because we aren't supposed to touch any
|
|
||||||
# of that - too many potential implementation issues.
|
|
||||||
#
|
|
||||||
# Apparently we're also not supposed to set our own dict directly
|
|
||||||
# in this particular function?...
|
|
||||||
return object.__setattr__(self, name, value)
|
|
||||||
else:
|
|
||||||
return super().__setitem__(name, value)
|
|
||||||
|
|
||||||
def __delattr__(self, name):
|
|
||||||
# We very *specifically* use self.__dict__ here, because we couldn't
|
|
||||||
# possibly delete a value that doesn't yet *exist* in our instance's
|
|
||||||
# namespace yet!
|
|
||||||
# This shouldn't be a problem, since this type should never have
|
|
||||||
# __slots__.
|
|
||||||
if name in self.__dict__:
|
|
||||||
# See __setattr__.
|
|
||||||
return object.__delattr__(self, name)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
del self[name]
|
|
||||||
except KeyError as err:
|
|
||||||
raise AttributeError(str(err))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _is_reserved(name):
|
|
||||||
"""Check if an attribute name is reserved for system use."""
|
|
||||||
# A very simple method.
|
|
||||||
result = name[:2] == name[-2:] == "__"
|
|
||||||
return result
|
|
||||||
|
|
||||||
def copy(self):
|
|
||||||
return type(self)(self)
|
|
||||||
|
|
||||||
__copy__ = copy
|
|
||||||
|
|
||||||
|
|
||||||
## end of http://code.activestate.com/recipes/473786/ }}}
|
|
||||||
|
|
||||||
|
|
||||||
class DefAttrDict(AttrDict):
|
|
||||||
default_factory = None
|
|
||||||
|
|
||||||
def __init__(self, default_factory=None, *args, **kwargs):
|
|
||||||
self.default_factory = default_factory
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "{}({!r}, {})".format(
|
|
||||||
type(self).__name__,
|
|
||||||
self.default_factory,
|
|
||||||
# We skip normal processing here, since AttrDict provides basic
|
|
||||||
# repr for classes in general, which we don't want.
|
|
||||||
dict.__repr__(self),
|
|
||||||
)
|
|
||||||
|
|
||||||
def __getitem__(self, name):
|
|
||||||
try:
|
|
||||||
result = super().__getitem__(name)
|
|
||||||
except KeyError:
|
|
||||||
result = None
|
|
||||||
if self.default_factory is not None:
|
|
||||||
result = self.default_factory()
|
|
||||||
self[name] = result
|
|
||||||
return result
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
try:
|
|
||||||
result = super().__getattr__(name)
|
|
||||||
except AttributeError:
|
|
||||||
# Detect special/reserved names.
|
|
||||||
if self._is_reserved(name):
|
|
||||||
# We shouldn't automatically fill these in.
|
|
||||||
# Pass this along.
|
|
||||||
raise
|
|
||||||
return result
|
|
||||||
|
|
||||||
def copy(self):
|
|
||||||
return type(self)(self.default_factory, self)
|
|
||||||
|
|
||||||
__copy__ = copy
|
|
||||||
|
|
||||||
|
|
||||||
# vim: set autoindent ts=4 sts=4 sw=4 textwidth=79 expandtab:
|
|
|
@ -2,10 +2,6 @@ __all__ = ["Color"]
|
||||||
|
|
||||||
# karxi: Copied from my old Textsub script. Please forgive the mess, and keep
|
# karxi: Copied from my old Textsub script. Please forgive the mess, and keep
|
||||||
# in mind that this may be phased out in the future.
|
# in mind that this may be phased out in the future.
|
||||||
|
|
||||||
|
|
||||||
from pnc.dep.attrdict import AttrDict
|
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import functools
|
import functools
|
||||||
import sys
|
import sys
|
||||||
|
@ -410,7 +406,7 @@ class Color:
|
||||||
|
|
||||||
# All of these are effectively equivalent to the Qt-provided colors, so they
|
# All of these are effectively equivalent to the Qt-provided colors, so they
|
||||||
# could be phased out - but there's no need to, yet.
|
# could be phased out - but there's no need to, yet.
|
||||||
_svg_colors = AttrDict()
|
_svg_colors = {}
|
||||||
_irc_colors = {}
|
_irc_colors = {}
|
||||||
_svg_colors.update(
|
_svg_colors.update(
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue