Compare commits
3 Commits
d81b4c84b8
...
d25beeda89
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d25beeda89 | ||
|
|
9d3e4b8d0c | ||
|
|
4903330e44 |
@ -87,6 +87,7 @@ class Config(object):
|
||||
OBS_PORT = 4455
|
||||
PLAY_SETTLE = 500000
|
||||
ROOT = os.environ.get('ROOT') or "/home/kae/music"
|
||||
ROWS_FROM_ZERO = True
|
||||
IMPORT_DESTINATION = os.path.join(ROOT, "Singles")
|
||||
SCROLL_TOP_MARGIN = 3
|
||||
START_GAP_WARNING_THRESHOLD = 500
|
||||
|
||||
@ -166,20 +166,6 @@ class PlaylistModel(QAbstractTableModel):
|
||||
# Fall through to no-op
|
||||
return QVariant()
|
||||
|
||||
def edit_role(self, row: int, column: int, prd: PlaylistRowData) -> QVariant:
|
||||
"""
|
||||
Return text for editing
|
||||
"""
|
||||
|
||||
if column == Col.TITLE.value:
|
||||
return QVariant(prd.title)
|
||||
if column == Col.ARTIST.value:
|
||||
return QVariant(prd.artist)
|
||||
if column == Col.NOTE.value:
|
||||
return QVariant(prd.note)
|
||||
|
||||
return QVariant()
|
||||
|
||||
def display_role(self, row: int, column: int, prd: PlaylistRowData) -> QVariant:
|
||||
"""
|
||||
Return text for display
|
||||
@ -241,9 +227,13 @@ class PlaylistModel(QAbstractTableModel):
|
||||
"""
|
||||
|
||||
if not index.isValid():
|
||||
return Qt.ItemFlag.ItemIsEnabled
|
||||
return Qt.ItemFlag.ItemIsDropEnabled
|
||||
|
||||
default = Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable
|
||||
default = (
|
||||
Qt.ItemFlag.ItemIsEnabled
|
||||
| Qt.ItemFlag.ItemIsSelectable
|
||||
| Qt.ItemFlag.ItemIsDragEnabled
|
||||
)
|
||||
if index.column() in [Col.TITLE.value, Col.ARTIST.value, Col.NOTE.value]:
|
||||
return default | Qt.ItemFlag.ItemIsEditable
|
||||
|
||||
@ -279,6 +269,9 @@ class PlaylistModel(QAbstractTableModel):
|
||||
return QVariant(Config.HEADER_BITRATE)
|
||||
elif section == Col.NOTE.value:
|
||||
return QVariant(Config.HEADER_NOTE)
|
||||
else:
|
||||
if Config.ROWS_FROM_ZERO:
|
||||
return QVariant(str(section))
|
||||
else:
|
||||
return QVariant(str(section + 1))
|
||||
|
||||
@ -350,3 +343,6 @@ class PlaylistModel(QAbstractTableModel):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def supportedDropActions(self):
|
||||
return Qt.DropAction.MoveAction | Qt.DropAction.CopyAction
|
||||
|
||||
122
app/playlists.py
122
app/playlists.py
@ -31,6 +31,9 @@ from PyQt6.QtWidgets import (
|
||||
QTableView,
|
||||
QTableWidgetItem,
|
||||
QWidget,
|
||||
QProxyStyle,
|
||||
QStyle,
|
||||
QStyleOption,
|
||||
)
|
||||
|
||||
from config import Config
|
||||
@ -45,6 +48,7 @@ from helpers import (
|
||||
set_track_metadata,
|
||||
)
|
||||
from log import log
|
||||
|
||||
from models import Playlists, PlaylistRows, Settings, Tracks, NoteColours
|
||||
|
||||
from playlistmodel import PlaylistModel
|
||||
@ -52,37 +56,8 @@ from playlistmodel import PlaylistModel
|
||||
if TYPE_CHECKING:
|
||||
from musicmuster import Window, MusicMusterSignals
|
||||
|
||||
# scene_change_re = re.compile(r"SetScene=\[([^[\]]*)\]")
|
||||
# section_header_cleanup_re = re.compile(r"(@\d\d:\d\d:\d\d.*)?(\+)?")
|
||||
# start_time_re = re.compile(r"@\d\d:\d\d:\d\d")
|
||||
|
||||
HEADER_NOTES_COLUMN = 2
|
||||
|
||||
# # Columns
|
||||
# Column = namedtuple("Column", ["idx", "heading"])
|
||||
# columns = {}
|
||||
# columns["userdata"] = Column(idx=0, heading=Config.COLUMN_NAME_AUTOPLAY)
|
||||
# columns["start_gap"] = Column(idx=1, heading=Config.COLUMN_NAME_LEADING_SILENCE)
|
||||
# columns["title"] = Column(idx=2, heading=Config.COLUMN_NAME_TITLE)
|
||||
# columns["artist"] = Column(idx=3, heading=Config.COLUMN_NAME_ARTIST)
|
||||
# columns["duration"] = Column(idx=4, heading=Config.COLUMN_NAME_LENGTH)
|
||||
# columns["start_time"] = Column(idx=5, heading=Config.COLUMN_NAME_START_TIME)
|
||||
# columns["end_time"] = Column(idx=6, heading=Config.COLUMN_NAME_END_TIME)
|
||||
# columns["lastplayed"] = Column(idx=7, heading=Config.COLUMN_NAME_LAST_PLAYED)
|
||||
# columns["bitrate"] = Column(idx=8, heading=Config.COLUMN_NAME_BITRATE)
|
||||
# columns["row_notes"] = Column(idx=9, heading=Config.COLUMN_NAME_NOTES)
|
||||
|
||||
# USERDATA = columns["userdata"].idx
|
||||
# START_GAP = columns["start_gap"].idx
|
||||
# TITLE = columns["title"].idx
|
||||
# ARTIST = columns["artist"].idx
|
||||
# DURATION = columns["duration"].idx
|
||||
# START_TIME = columns["start_time"].idx
|
||||
# END_TIME = columns["end_time"].idx
|
||||
# LASTPLAYED = columns["lastplayed"].idx
|
||||
# BITRATE = columns["bitrate"].idx
|
||||
# ROW_NOTES = columns["row_notes"].idx
|
||||
|
||||
|
||||
class EscapeDelegate(QStyledItemDelegate):
|
||||
"""
|
||||
@ -157,6 +132,25 @@ class EscapeDelegate(QStyledItemDelegate):
|
||||
editor.setGeometry(option.rect)
|
||||
|
||||
|
||||
class PlaylistStyle(QProxyStyle):
|
||||
def drawPrimitive(self, element, option, painter, widget=None):
|
||||
"""
|
||||
Draw a line across the entire row rather than just the column
|
||||
we're hovering over. This may not always work depending on global
|
||||
style - for instance I think it won't work on OSX.
|
||||
"""
|
||||
if (
|
||||
element == QStyle.PrimitiveElement.PE_IndicatorItemViewItemDrop
|
||||
and not option.rect.isNull()
|
||||
):
|
||||
option_new = QStyleOption(option)
|
||||
option_new.rect.setLeft(0)
|
||||
if widget:
|
||||
option_new.rect.setRight(widget.width())
|
||||
option = option_new
|
||||
super().drawPrimitive(element, option, painter, widget)
|
||||
|
||||
|
||||
class PlaylistTab(QTableView):
|
||||
def __init__(
|
||||
self,
|
||||
@ -178,17 +172,15 @@ class PlaylistTab(QTableView):
|
||||
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
# self.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked)
|
||||
self.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel)
|
||||
# This dancing is to satisfy mypy
|
||||
# Drag and drop setup
|
||||
# self.setAcceptDrops(True)
|
||||
# viewport = self.viewport()
|
||||
# if viewport:
|
||||
# viewport.setAcceptDrops(True)
|
||||
# self.setDragDropOverwriteMode(False)
|
||||
# self.setDropIndicatorShown(True)
|
||||
# self.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
|
||||
# self.setDragEnabled(False)
|
||||
self.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
|
||||
self.setDragDropOverwriteMode(False)
|
||||
self.setAcceptDrops(True)
|
||||
# Set our custom style - this draws the drop indicator across the whole row
|
||||
self.setStyle(PlaylistStyle())
|
||||
|
||||
# TODO: change this later to only enable drags when multiple
|
||||
# rows selected
|
||||
self.setDragEnabled(True)
|
||||
# Prepare for context menu
|
||||
# self.menu = QMenu()
|
||||
# self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||
@ -221,6 +213,24 @@ class PlaylistTab(QTableView):
|
||||
|
||||
# ########## Events other than cell editing ##########
|
||||
|
||||
def dropEvent(self, event):
|
||||
if event.source() is not self or (
|
||||
event.dropAction() != Qt.DropAction.MoveAction
|
||||
and self.dragDropMode() != QAbstractItemView.InternalMove
|
||||
):
|
||||
super().dropEvent(event)
|
||||
|
||||
from_rows = list(set([a.row() for a in self.selectedIndexes()]))
|
||||
to_row = self.indexAt(event.position().toPoint()).row()
|
||||
if (
|
||||
0 <= min(from_rows) <= self.model().rowCount()
|
||||
and 0 <= max(from_rows) <= self.model().rowCount()
|
||||
and 0 <= to_row <= self.model().rowCount()
|
||||
):
|
||||
print(f"move_rows({from_rows=}, {to_row=})")
|
||||
event.accept()
|
||||
super().dropEvent(event)
|
||||
|
||||
# def dropEvent(self, event: Optional[QDropEvent]) -> None:
|
||||
# """
|
||||
# Handle drag/drop of rows
|
||||
@ -510,7 +520,7 @@ class PlaylistTab(QTableView):
|
||||
"""Unselect all tracks and reset drag mode"""
|
||||
|
||||
self.clearSelection()
|
||||
self.setDragEnabled(False)
|
||||
# self.setDragEnabled(False)
|
||||
|
||||
# def get_new_row_number(self) -> int:
|
||||
# """
|
||||
@ -1246,7 +1256,7 @@ class PlaylistTab(QTableView):
|
||||
self.save_playlist(session)
|
||||
|
||||
# Reset drag mode
|
||||
self.setDragEnabled(False)
|
||||
# self.setDragEnabled(False)
|
||||
|
||||
self._update_start_end_times(session)
|
||||
|
||||
@ -1304,21 +1314,21 @@ class PlaylistTab(QTableView):
|
||||
|
||||
return self._plrid_to_row_number(next_track.plr_id)
|
||||
|
||||
@staticmethod
|
||||
def _get_note_text_time(text: str) -> Optional[datetime]:
|
||||
"""Return datetime specified as @hh:mm:ss in text"""
|
||||
# @staticmethod
|
||||
# def _get_note_text_time(text: str) -> Optional[datetime]:
|
||||
# """Return datetime specified as @hh:mm:ss in text"""
|
||||
|
||||
try:
|
||||
match = start_time_re.search(text)
|
||||
except TypeError:
|
||||
return None
|
||||
if not match:
|
||||
return None
|
||||
# try:
|
||||
# match = start_time_re.search(text)
|
||||
# except TypeError:
|
||||
# return None
|
||||
# if not match:
|
||||
# return None
|
||||
|
||||
try:
|
||||
return datetime.strptime(match.group(0)[1:], Config.NOTE_TIME_FORMAT)
|
||||
except ValueError:
|
||||
return None
|
||||
# try:
|
||||
# return datetime.strptime(match.group(0)[1:], Config.NOTE_TIME_FORMAT)
|
||||
# except ValueError:
|
||||
# return None
|
||||
|
||||
def _get_played_rows(self, session: scoped_session) -> List[int]:
|
||||
"""
|
||||
@ -2361,7 +2371,7 @@ class PlaylistTab(QTableView):
|
||||
self._reorder_rows(new_order)
|
||||
|
||||
# Reset drag mode to allow row selection by dragging
|
||||
self.setDragEnabled(False)
|
||||
# self.setDragEnabled(False)
|
||||
|
||||
# Save playlist
|
||||
with Session() as session:
|
||||
@ -2384,7 +2394,7 @@ class PlaylistTab(QTableView):
|
||||
]
|
||||
|
||||
# Reset drag mode to allow row selection by dragging
|
||||
self.setDragEnabled(False)
|
||||
# self.setDragEnabled(False)
|
||||
|
||||
# Save playlist
|
||||
with Session() as session:
|
||||
|
||||
190
archive/DragAndDropReference.py
Executable file
190
archive/DragAndDropReference.py
Executable file
@ -0,0 +1,190 @@
|
||||
#!/usr/bin/python3
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
||||
|
||||
# PyQt Functionality Snippet by Apocalyptech
|
||||
# "Licensed" in the Public Domain under CC0 1.0 Universal (CC0 1.0)
|
||||
# Public Domain Dedication. Use it however you like!
|
||||
#
|
||||
# https://creativecommons.org/publicdomain/zero/1.0/
|
||||
# https://creativecommons.org/publicdomain/zero/1.0/legalcode
|
||||
|
||||
from PyQt6 import QtWidgets, QtCore
|
||||
|
||||
|
||||
# class MyModel(QtGui.QStandardItemModel):
|
||||
class MyModel(QtCore.QAbstractTableModel):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
def columnCount(self, parent=None):
|
||||
return 5
|
||||
|
||||
def rowCount(self, parent=None):
|
||||
return 20
|
||||
|
||||
# def headerData(self, column: int, orientation, role: QtCore.Qt.ItemDataRole):
|
||||
# return (('Regex', 'Category')[column]
|
||||
# if role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Horizontal
|
||||
# else None)
|
||||
|
||||
def headerData(self, column, orientation, role):
|
||||
if role == QtCore.Qt.ItemDataRole.DisplayRole and orientation == QtCore.Qt.Orientation.Horizontal:
|
||||
return f"{column=}"
|
||||
return None
|
||||
|
||||
def data(self, index: QtCore.QModelIndex, role: QtCore.Qt.ItemDataRole):
|
||||
if not index.isValid() or role not in {
|
||||
QtCore.Qt.ItemDataRole.DisplayRole,
|
||||
QtCore.Qt.ItemDataRole.EditRole,
|
||||
}:
|
||||
return None
|
||||
# return (self._data[index.row()][index.column()] if index.row() < len(self._data) else
|
||||
# "edit me" if role == QtCore.Qt.DisplayRole else "")
|
||||
|
||||
# def data(self, index, role):
|
||||
# if not index.isValid() or role not in [QtCore.Qt.DisplayRole,
|
||||
# QtCore.Qt.EditRole]:
|
||||
# return None
|
||||
# return (self._data[index.row()][index.column()] if index.row() < len(self._data) else
|
||||
# "edit me" if role == QtCore.Qt.DisplayRole else "")
|
||||
|
||||
row = index.row()
|
||||
column = index.column()
|
||||
return f"Row {row}, Col {column}"
|
||||
|
||||
def flags(self, index: QtCore.QModelIndex) -> QtCore.Qt.ItemFlag:
|
||||
# https://doc.qt.io/qt-5/qt.html#ItemFlag-enum
|
||||
if not index.isValid():
|
||||
return QtCore.Qt.ItemFlag.ItemIsEnabled
|
||||
if index.row() < 20:
|
||||
return (
|
||||
QtCore.Qt.ItemFlag.ItemIsEnabled
|
||||
| QtCore.Qt.ItemFlag.ItemIsEditable
|
||||
| QtCore.Qt.ItemFlag.ItemIsSelectable
|
||||
| QtCore.Qt.ItemFlag.ItemIsDragEnabled
|
||||
)
|
||||
return QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsEditable
|
||||
|
||||
# def flags(self, index):
|
||||
# if not index.isValid():
|
||||
# return QtCore.Qt.ItemIsDropEnabled
|
||||
# if index.row() < 5:
|
||||
# return (
|
||||
# QtCore.Qt.ItemIsEnabled
|
||||
# | QtCore.Qt.ItemIsEditable
|
||||
# | QtCore.Qt.ItemIsSelectable
|
||||
# | QtCore.Qt.ItemIsDragEnabled
|
||||
# )
|
||||
# return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable
|
||||
|
||||
# def supportedDragOptions(self):
|
||||
# return QtCore.Qt.MoveAction | QtCore.Qt.CopyAction
|
||||
|
||||
# def supportedDropActions(self) -> bool:
|
||||
# return QtCore.Qt.MoveAction | QtCore.Qt.CopyAction
|
||||
|
||||
def relocateRow(self, row_source, row_target) -> None:
|
||||
return
|
||||
row_a, row_b = max(row_source, row_target), min(row_source, row_target)
|
||||
self.beginMoveRows(
|
||||
QtCore.QModelIndex(), row_a, row_a, QtCore.QModelIndex(), row_b
|
||||
)
|
||||
self._data.insert(row_target, self._data.pop(row_source))
|
||||
self.endMoveRows()
|
||||
|
||||
def supportedDropActions(self):
|
||||
return QtCore.Qt.DropAction.MoveAction | QtCore.Qt.DropAction.CopyAction
|
||||
|
||||
# def relocateRow(self, src, dst):
|
||||
# print("relocateRow")
|
||||
|
||||
# def dropMimeData(self, data, action, row, col, parent):
|
||||
# """
|
||||
# Always move the entire row, and don't allow column "shifting"
|
||||
# """
|
||||
# # return super().dropMimeData(data, action, row, 0, parent)
|
||||
# print("dropMimeData")
|
||||
# super().dropMimeData(data, action, row, col, parent)
|
||||
|
||||
|
||||
class MyStyle(QtWidgets.QProxyStyle):
|
||||
def drawPrimitive(self, element, option, painter, widget=None):
|
||||
"""
|
||||
Draw a line across the entire row rather than just the column
|
||||
we're hovering over. This may not always work depending on global
|
||||
style - for instance I think it won't work on OSX.
|
||||
"""
|
||||
if element == QtWidgets.QStyle.PrimitiveElement.PE_IndicatorItemViewItemDrop and not option.rect.isNull():
|
||||
option_new = QtWidgets.QStyleOption(option)
|
||||
option_new.rect.setLeft(0)
|
||||
if widget:
|
||||
option_new.rect.setRight(widget.width())
|
||||
option = option_new
|
||||
super().drawPrimitive(element, option, painter, widget)
|
||||
|
||||
|
||||
class MyTableView(QtWidgets.QTableView):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self.verticalHeader().hide()
|
||||
self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
self.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection)
|
||||
self.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.InternalMove)
|
||||
self.setDragDropOverwriteMode(False)
|
||||
self.setAcceptDrops(True)
|
||||
# self.horizontalHeader().hide()
|
||||
# self.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
|
||||
# self.setShowGrid(False)
|
||||
|
||||
# Set our custom style - this draws the drop indicator across the whole row
|
||||
self.setStyle(MyStyle())
|
||||
|
||||
# Set our custom model - this prevents row "shifting"
|
||||
# self.model = MyModel()
|
||||
# self.setModel(self.model)
|
||||
self.setModel(MyModel())
|
||||
|
||||
# for (idx, data) in enumerate(['foo', 'bar', 'baz']):
|
||||
# item_1 = QtGui.QStandardItem('Item {}'.format(idx))
|
||||
# item_1.setEditable(False)
|
||||
# item_1.setDropEnabled(False)
|
||||
|
||||
# item_2 = QtGui.QStandardItem(data)
|
||||
# item_2.setEditable(False)
|
||||
# item_2.setDropEnabled(False)
|
||||
|
||||
# self.model.appendRow([item_1, item_2])
|
||||
|
||||
def dropEvent(self, event):
|
||||
if event.source() is not self or (
|
||||
event.dropAction() != QtCore.Qt.DropAction.MoveAction
|
||||
and self.dragDropMode() != QtWidgets.QAbstractItemView.InternalMove
|
||||
):
|
||||
super().dropEvent(event)
|
||||
|
||||
from_rows = list(set([a.row() for a in self.selectedIndexes()]))
|
||||
to_row = self.indexAt(event.position().toPoint()).row()
|
||||
if (
|
||||
0 <= min(from_rows) <= self.model().rowCount()
|
||||
and 0 <= max(from_rows) <= self.model().rowCount()
|
||||
and 0 <= to_row <= self.model().rowCount()
|
||||
):
|
||||
print(f"move_rows({from_rows=}, {to_row=})")
|
||||
event.accept()
|
||||
super().dropEvent(event)
|
||||
|
||||
|
||||
class Testing(QtWidgets.QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
view = MyTableView(self)
|
||||
view.setModel(MyModel())
|
||||
self.setCentralWidget(view)
|
||||
self.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QtWidgets.QApplication([])
|
||||
test = Testing()
|
||||
raise SystemExit(app.exec())
|
||||
46
poetry.lock
generated
46
poetry.lock
generated
@ -1030,6 +1030,23 @@ files = [
|
||||
{file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pdbp"
|
||||
version = "1.5.0"
|
||||
description = "pdbp (Pdb+): A drop-in replacement for pdb and pdbpp."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pdbp-1.5.0-py3-none-any.whl", hash = "sha256:7640598c336ec3e3e0b2aeec71d20a1e810ba49e3e1b3effac5b862a798dea7d"},
|
||||
{file = "pdbp-1.5.0.tar.gz", hash = "sha256:23e03897fe950794a487238b64d8b0cec66760083c4697e3b7bc5ca0fae617ea"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = ">=0.4.6", markers = "platform_system == \"Windows\""}
|
||||
pygments = ">=2.16.1"
|
||||
tabcompleter = ">=1.3.0"
|
||||
|
||||
[[package]]
|
||||
name = "pexpect"
|
||||
version = "4.8.0"
|
||||
@ -1452,6 +1469,18 @@ files = [
|
||||
[package.dependencies]
|
||||
numpy = ">=1.20.0"
|
||||
|
||||
[[package]]
|
||||
name = "pyreadline3"
|
||||
version = "3.4.1"
|
||||
description = "A python implementation of GNU readline."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"},
|
||||
{file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.4.2"
|
||||
@ -1915,6 +1944,21 @@ files = [
|
||||
{file = "stackprinter-0.2.10.tar.gz", hash = "sha256:99d1ea6b91ffad96b28241edd7bcf071752b0cf694cab58d2335df5353acd086"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tabcompleter"
|
||||
version = "1.3.0"
|
||||
description = "tabcompleter --- Autocompletion in the Python console."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "tabcompleter-1.3.0-py3-none-any.whl", hash = "sha256:59dfe825f4d88a51d486c0a513763eca6224f2146518d185ee2ebfc4f2398b80"},
|
||||
{file = "tabcompleter-1.3.0.tar.gz", hash = "sha256:47b9d4f783d14ebca5c66223c7f82cc1ef89f7313ba9ea0ce75265670178bb6e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyreadline3 = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "text-unidecode"
|
||||
version = "1.3"
|
||||
@ -2148,4 +2192,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "97f122b0c15850e806e764ab7d3df23ce115e8aa9cc7a775c64834b18beef664"
|
||||
content-hash = "514b699dbd1e579adcad3ee6112c632bbd01bc801377b27a5cbe7cebd35d5995"
|
||||
|
||||
@ -42,6 +42,7 @@ furo = "^2023.5.20"
|
||||
black = "^23.3.0"
|
||||
flakehell = "^0.9.0"
|
||||
mypy = "^1.6.0"
|
||||
pdbp = "^1.5.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user