mirror of
https://github.com/Febbweiss/mopidy-touchscreen.git
synced 2026-03-04 22:25:39 +00:00
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,4 +7,4 @@
|
|||||||
MANIFEST
|
MANIFEST
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
.idea/
|
mopidy_touchscreen/.idea/
|
||||||
|
|||||||
10
README.rst
10
README.rst
@@ -3,22 +3,22 @@ Mopidy-Touchscreen
|
|||||||
****************************
|
****************************
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/v/Mopidy-Touchscreen.svg?style=flat
|
.. image:: https://img.shields.io/pypi/v/Mopidy-Touchscreen.svg?style=flat
|
||||||
:target: https://pypi.python.org/pypi/Mopidy-Touchscreen/
|
:target: https://pypi.python.org/pypi/Mopidy-Touchscreen/
|
||||||
:alt: Latest PyPI version
|
:alt: Latest PyPI version
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/dm/Mopidy-Touchscreen.svg?style=flat
|
.. image:: https://img.shields.io/pypi/dm/Mopidy-Touchscreen.svg?style=flat
|
||||||
:target: https://pypi.python.org/pypi/Mopidy-Touchscreen/
|
:target: https://pypi.python.org/pypi/Mopidy-Touchscreen/
|
||||||
:alt: Number of PyPI downloads
|
:alt: Number of PyPI downloads
|
||||||
|
|
||||||
.. image:: https://img.shields.io/travis/9and3r/modipy-touchscreen/master.png?style=flat
|
.. image:: https://img.shields.io/travis/9and3r/modipy-touchscreen/master.png?style=flat
|
||||||
:target: https://travis-ci.org/9and3r/modipy-touchscreen
|
:target: https://travis-ci.org/9and3r/modipy-touchscreen
|
||||||
:alt: Travis CI build status
|
:alt: Travis CI build status
|
||||||
|
|
||||||
.. image:: https://img.shields.io/coveralls/9and3r/modipy-touchscreen/master.svg?style=flat
|
.. image:: https://img.shields.io/coveralls/9and3r/modipy-touchscreen/master.svg?style=flat
|
||||||
:target: https://coveralls.io/r/9and3r/modipy-touchscreen?branch=master
|
:target: https://coveralls.io/r/9and3r/modipy-touchscreen?branch=master
|
||||||
:alt: Test coverage
|
:alt: Test coverage
|
||||||
|
|
||||||
Extension for displaying track info and controlling Mopidy from a touch screen using `PyGame <http://www.pygame.org/>`_/SDL.
|
Extension for displaying track info and controlling Mopidy from a touch screen using `PyGame <http://www.pygame.org/>`_/SDL.
|
||||||
|
|
||||||
Cover images are downloaded from `last.fm <http://www.last.fm/api>`_
|
Cover images are downloaded from `last.fm <http://www.last.fm/api>`_
|
||||||
|
|
||||||
|
|||||||
24
docs/conf.py
24
docs/conf.py
@@ -18,7 +18,7 @@ import os
|
|||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
#sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
# -- General configuration ------------------------------------------------
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
@@ -182,22 +182,22 @@ htmlhelp_basename = 'Mopidy-Touchscreendoc'
|
|||||||
# -- Options for LaTeX output ---------------------------------------------
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
#'papersize': 'letterpaper',
|
#'papersize': 'letterpaper',
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
#'pointsize': '10pt',
|
#'pointsize': '10pt',
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
# Additional stuff for the LaTeX preamble.
|
||||||
#'preamble': '',
|
#'preamble': '',
|
||||||
}
|
}
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title,
|
# (source start file, target name, title,
|
||||||
# author, documentclass [howto, manual, or own class]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('index', 'Mopidy-Touchscreen.tex', u'Mopidy-Touchscreen Documentation',
|
('index', 'Mopidy-Touchscreen.tex', u'Mopidy-Touchscreen Documentation',
|
||||||
u'9and3r', 'manual'),
|
u'9and3r', 'manual'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
@@ -240,9 +240,9 @@ man_pages = [
|
|||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('index', 'Mopidy-Touchscreen', u'Mopidy-Touchscreen Documentation',
|
('index', 'Mopidy-Touchscreen', u'Mopidy-Touchscreen Documentation',
|
||||||
u'9and3r', 'Mopidy-Touchscreen', 'One line description of project.',
|
u'9and3r', 'Mopidy-Touchscreen', 'One line description of project.',
|
||||||
'Miscellaneous'),
|
'Miscellaneous'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
# Documents to append as an appendix to all manuals.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
.. Mopidy-Touchscreen documentation master file, created by
|
.. Mopidy-Touchscreen documentation master file, created by
|
||||||
sphinx-quickstart on Mon Aug 4 00:48:14 2014.
|
sphinx-quickstart on Mon Aug 4 00:48:14 2014.
|
||||||
You can adapt this file completely to your liking, but it should at least
|
You can adapt this file completely to your liking, but it should at least
|
||||||
contain the root `toctree` directive.
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
Welcome to Mopidy-Touchscreen's documentation!
|
Welcome to Mopidy-Touchscreen's documentation!
|
||||||
==============================================
|
==============================================
|
||||||
@@ -9,7 +9,7 @@ Welcome to Mopidy-Touchscreen's documentation!
|
|||||||
Contents:
|
Contents:
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,5 +36,5 @@ class Extension(ext.Extension):
|
|||||||
def setup(self, registry):
|
def setup(self, registry):
|
||||||
registry.add('frontend', TouchScreen)
|
registry.add('frontend', TouchScreen)
|
||||||
|
|
||||||
# Backend used for controling volume
|
#Backend used for controling volume
|
||||||
registry.add('backend', TouchScreenBackend)
|
registry.add('backend', TouchScreenBackend)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class DynamicBackground():
|
|||||||
|
|
||||||
|
|
||||||
# Returns an array with 3 integers in range of 0-255
|
# Returns an array with 3 integers in range of 0-255
|
||||||
# The sum of the three integers will be lower than 255*2 (510) to avoid very bright colors
|
#The sum of the three integers will be lower than 255*2 (510) to avoid very bright colors
|
||||||
#White text should be seen ok with this background color
|
#White text should be seen ok with this background color
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,6 @@ class LibraryScreen():
|
|||||||
self.manager.core.tracklist.add(uri=uri)
|
self.manager.core.tracklist.add(uri=uri)
|
||||||
self.manager.core.playback.play()
|
self.manager.core.playback.play()
|
||||||
else:
|
else:
|
||||||
# TODO: add folder to tracks to play
|
#TODO: add folder to tracks to play
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class ListView():
|
|||||||
self.set_list([])
|
self.set_list([])
|
||||||
self.selected = []
|
self.selected = []
|
||||||
|
|
||||||
# Sets the list for the lisview. It should be an iterable of strings
|
#Sets the list for the lisview. It should be an iterable of strings
|
||||||
def set_list(self, item_list):
|
def set_list(self, item_list):
|
||||||
self.list = item_list
|
self.list = item_list
|
||||||
self.list_size = len(item_list)
|
self.list_size = len(item_list)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class MainScreen():
|
|||||||
(width, self.size[1]))
|
(width, self.size[1]))
|
||||||
self.touch_text_manager.set_object("track_name", label)
|
self.touch_text_manager.set_object("track_name", label)
|
||||||
|
|
||||||
# Album name
|
#Album name
|
||||||
label = TextItem(self.fonts['base'], MainScreen.get_track_album_name(track), (x, self.base_size * 3),
|
label = TextItem(self.fonts['base'], MainScreen.get_track_album_name(track), (x, self.base_size * 3),
|
||||||
(width, self.size[1]))
|
(width, self.size[1]))
|
||||||
self.touch_text_manager.set_object("album_name", label)
|
self.touch_text_manager.set_object("album_name", label)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class MenuScreen():
|
|||||||
None)
|
None)
|
||||||
self.screen_objects.set_touch_object("exit", button)
|
self.screen_objects.set_touch_object("exit", button)
|
||||||
|
|
||||||
# Shutdown button
|
#Shutdown button
|
||||||
button = TouchAndTextItem(self.manager.fonts['icon'], u"\ue60b", (0, self.base_size * 2), None)
|
button = TouchAndTextItem(self.manager.fonts['icon'], u"\ue60b", (0, self.base_size * 2), None)
|
||||||
self.screen_objects.set_touch_object("shutdown_icon", button)
|
self.screen_objects.set_touch_object("shutdown_icon", button)
|
||||||
button = TouchAndTextItem(self.manager.fonts['base'], "Shutdown", (button.get_right_pos(), self.base_size * 2),
|
button = TouchAndTextItem(self.manager.fonts['base'], "Shutdown", (button.get_right_pos(), self.base_size * 2),
|
||||||
@@ -62,7 +62,7 @@ class MenuScreen():
|
|||||||
elif key == "ip":
|
elif key == "ip":
|
||||||
self.check_connection()
|
self.check_connection()
|
||||||
|
|
||||||
# Will check internet connection
|
#Will check internet connection
|
||||||
def check_connection(self):
|
def check_connection(self):
|
||||||
try:
|
try:
|
||||||
self.manager.set_connection(False, True)
|
self.manager.set_connection(False, True)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class ScreenManager():
|
|||||||
self.background = DynamicBackground()
|
self.background = DynamicBackground()
|
||||||
self.current_screen = 0
|
self.current_screen = 0
|
||||||
self.base_size = self.size[1] / 8
|
self.base_size = self.size[1] / 8
|
||||||
font = resource_filename(Requirement.parse("mopidy-touchscreen"), "mopidy_touchscreen/icomoon.ttf")
|
font = resource_filename(Requirement.parse("mopidy-touchscreen"),"mopidy_touchscreen/icomoon.ttf")
|
||||||
self.fonts['base'] = pygame.font.SysFont("verdana", self.base_size)
|
self.fonts['base'] = pygame.font.SysFont("verdana", self.base_size)
|
||||||
self.fonts['icon'] = pygame.font.Font(font, self.base_size)
|
self.fonts['icon'] = pygame.font.Font(font, self.base_size)
|
||||||
try:
|
try:
|
||||||
@@ -52,7 +52,7 @@ class ScreenManager():
|
|||||||
self.screen_objects_manager.set_touch_object("pause_play", button)
|
self.screen_objects_manager.set_touch_object("pause_play", button)
|
||||||
x = button.get_right_pos()
|
x = button.get_right_pos()
|
||||||
|
|
||||||
# Random
|
#Random
|
||||||
button = TouchAndTextItem(self.fonts['icon'], u"\ue629 ", (x, 0), None)
|
button = TouchAndTextItem(self.fonts['icon'], u"\ue629 ", (x, 0), None)
|
||||||
self.screen_objects_manager.set_touch_object("random", button)
|
self.screen_objects_manager.set_touch_object("random", button)
|
||||||
x = button.get_right_pos()
|
x = button.get_right_pos()
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class TouchScreen(pykka.ThreadingActor, core.CoreListener):
|
|||||||
screen = pygame.display.set_mode(self.screen_size, pygame.FULLSCREEN)
|
screen = pygame.display.set_mode(self.screen_size, pygame.FULLSCREEN)
|
||||||
else:
|
else:
|
||||||
screen = pygame.display.set_mode(self.screen_size)
|
screen = pygame.display.set_mode(self.screen_size)
|
||||||
pygame.mouse.set_visible(self.cursor)
|
pygame.mouse.set_visible(self.cursor)
|
||||||
while self.running:
|
while self.running:
|
||||||
clock.tick(15)
|
clock.tick(15)
|
||||||
screen.blit(self.screen_manager.update(), (0, 0))
|
screen.blit(self.screen_manager.update(), (0, 0))
|
||||||
|
|||||||
@@ -3,16 +3,18 @@ import logging
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TouchTextManager():
|
class TouchTextManager():
|
||||||
def __init__(self, size, base_size):
|
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self,size,base_size):
|
||||||
self.size = size
|
self.size = size
|
||||||
self.base_size = base_size
|
self.base_size = base_size
|
||||||
self.touch_objects = {}
|
self.touch_objects = {}
|
||||||
self.text_objects = {}
|
self.text_objects = {}
|
||||||
|
|
||||||
def add_object(self, key, text, pos, pos2, color):
|
def add_object(self, key, text, pos, pos2, color):
|
||||||
self.text_objects[key] = TextItem(text, pos, pos2, color, self.base_size)
|
self.text_objects[key] = TextItem(text, pos,pos2,color,self.base_size)
|
||||||
|
|
||||||
def get_object(self, key):
|
def get_object(self, key):
|
||||||
return self.text_objects[key]
|
return self.text_objects[key]
|
||||||
@@ -20,11 +22,11 @@ class TouchTextManager():
|
|||||||
def add_touch_object(self, key, text, pos, color):
|
def add_touch_object(self, key, text, pos, color):
|
||||||
self.touch_objects['key'] = TouchAndTextItem(text, pos, color, self.base_size)
|
self.touch_objects['key'] = TouchAndTextItem(text, pos, color, self.base_size)
|
||||||
|
|
||||||
def get_touch_object(self, key):
|
def get_touch_object(self,key):
|
||||||
return self.touch_objects['key']
|
return self.touch_objects['key']
|
||||||
|
|
||||||
def add_progressbar(self, key, pos, pos2, max):
|
def add_progressbar(self, key, pos, pos2, max):
|
||||||
self.touch_objects['key'] = Progressbar(pos, pos2, max)
|
self.touch_objects['key'] = Progressbar(pos,pos2,max)
|
||||||
|
|
||||||
def render(self, surface):
|
def render(self, surface):
|
||||||
for key in self.text_objects:
|
for key in self.text_objects:
|
||||||
@@ -35,19 +37,21 @@ class TouchTextManager():
|
|||||||
|
|
||||||
|
|
||||||
class BaseItem():
|
class BaseItem():
|
||||||
def __init__(self, pos, pos2):
|
|
||||||
|
def __init__(self,pos,pos2):
|
||||||
self.pos = pos
|
self.pos = pos
|
||||||
self.pos2 = pos2
|
self.pos2 = pos2
|
||||||
self.size = [0, 0]
|
self.size=[0,0]
|
||||||
self.size[0] = self.pos2[0] - self.pos[0]
|
self.size[0] = self.pos2[0] - self.pos[0]
|
||||||
self.size[1] = self.pos2[1] - self.pos[1]
|
self.size[1] = self.pos2[1] - self.pos[1]
|
||||||
self.rect = pygame.Rect(0, 0, self.size[0], self.size[1])
|
self.rect = pygame.Rect(0,0,self.size[0],self.size[1])
|
||||||
|
|
||||||
|
|
||||||
class TextItem(BaseItem):
|
class TextItem(BaseItem):
|
||||||
def __init__(self, text, pos, pos2, color, text_size):
|
|
||||||
|
def __init__(self, text, pos,pos2, color,text_size):
|
||||||
if pos2 is not None:
|
if pos2 is not None:
|
||||||
BaseItem.__init__(self, pos, pos2)
|
BaseItem.__init__(self,pos,pos2)
|
||||||
self.text_size = text_size
|
self.text_size = text_size
|
||||||
self.font = pygame.font.SysFont("arial", text_size)
|
self.font = pygame.font.SysFont("arial", text_size)
|
||||||
self.text = text
|
self.text = text
|
||||||
@@ -66,7 +70,7 @@ class TextItem(BaseItem):
|
|||||||
else:
|
else:
|
||||||
self.fit_vertical = True
|
self.fit_vertical = True
|
||||||
else:
|
else:
|
||||||
BaseItem.__init__(self, pos, (pos[0] + self.box.get_rect().width, pos[1] + self.box.get_rect().height))
|
BaseItem.__init__(self,pos,(pos[0]+self.box.get_rect().width,pos[1]+self.box.get_rect().height))
|
||||||
self.fit_horizontal = True
|
self.fit_horizontal = True
|
||||||
self.fit_vertical = True
|
self.fit_vertical = True
|
||||||
|
|
||||||
@@ -89,49 +93,50 @@ class TextItem(BaseItem):
|
|||||||
else:
|
else:
|
||||||
self.step = self.step + 1
|
self.step = self.step + 1
|
||||||
|
|
||||||
def render(self, surface):
|
def render(self,surface):
|
||||||
if self.fit_horizontal:
|
if self.fit_horizontal:
|
||||||
self.box
|
self.box
|
||||||
else:
|
else:
|
||||||
self.box = self.font.render(self.text, True, self.color)
|
self.box = self.font.render(self.text, True, self.color)
|
||||||
surface.blit(self.box, self.pos, area=self.rect)
|
surface.blit(self.box,self.pos,area=self.rect)
|
||||||
|
|
||||||
def set_text(self, text):
|
def set_text(self, text):
|
||||||
self.__init__(text, self.pos, self.pos2, self.color, self.text_size)
|
self.__init__(text,self.pos,self.pos2,self.color,self.text_size)
|
||||||
|
|
||||||
|
|
||||||
class TouchObject(BaseItem):
|
class TouchObject(BaseItem):
|
||||||
def __init__(self, pos, pos2):
|
|
||||||
BaseItem.__init__(self, pos, pos2)
|
def __init__(self,pos,pos2):
|
||||||
|
BaseItem.__init__(self,pos,pos2)
|
||||||
self.active = False
|
self.active = False
|
||||||
self.background_box = pygame.Surface(self.size)
|
self.background_box = pygame.Surface(self.size)
|
||||||
self.background_box.fill((0, 128, 255))
|
self.background_box.fill((0,128,255))
|
||||||
|
|
||||||
def render(self, surface):
|
def render(self,surface):
|
||||||
surface.blit(self.background_box, self.pos)
|
surface.blit(self.background_box, self.pos)
|
||||||
|
|
||||||
|
|
||||||
class TouchAndTextItem(TouchObject, TextItem):
|
class TouchAndTextItem(TouchObject, TextItem):
|
||||||
def __init__(self, text, pos, color, text_size):
|
|
||||||
TextItem.__init__(self, text, pos, None, color, text_size)
|
def __init__(self, text, pos, color,text_size):
|
||||||
TouchObject.__init__(self, pos, self.pos2)
|
TextItem.__init__(self,text, pos,None, color,text_size)
|
||||||
|
TouchObject.__init__(self,pos,self.pos2)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
TextItem.update()
|
TextItem.update()
|
||||||
|
|
||||||
def render(self, surface):
|
def render(self,surface):
|
||||||
TouchObject.render(self, surface)
|
TouchObject.render(self,surface)
|
||||||
TextItem.render(self, surface)
|
TextItem.render(self,surface)
|
||||||
|
|
||||||
|
|
||||||
class Progressbar(BaseItem):
|
class Progressbar(BaseItem):
|
||||||
|
|
||||||
def __init__(self, pos, pos2, max):
|
def __init__(self, pos, pos2, max):
|
||||||
BaseItem.__init__(self, pos, pos2)
|
BaseItem.__init__(self, pos, pos2)
|
||||||
logger.error(pos2)
|
logger.error(pos2)
|
||||||
self.value = 0
|
self.value = 0
|
||||||
self.max = max
|
self.max = max
|
||||||
self.back_color = (0, 0, 0)
|
self.back_color = (0,0,0)
|
||||||
self.main_color = (255, 255, 255)
|
self.main_color = (255,255,255)
|
||||||
self.surface = pygame.Surface(self.size)
|
self.surface = pygame.Surface(self.size)
|
||||||
self.surface.fill(self.back_color)
|
self.surface.fill(self.back_color)
|
||||||
|
|
||||||
@@ -145,6 +150,6 @@ class Progressbar(BaseItem):
|
|||||||
self.value = value
|
self.value = value
|
||||||
self.surface.fill(self.back_color)
|
self.surface.fill(self.back_color)
|
||||||
pos_pixel = value * self.size[0] / self.max
|
pos_pixel = value * self.size[0] / self.max
|
||||||
rect = pygame.Rect(0, 0, pos_pixel, self.size[1])
|
rect = pygame.Rect(0,0,pos_pixel,self.size[1])
|
||||||
self.surface.fill(self.main_color, rect)
|
self.surface.fill(self.main_color, rect)
|
||||||
|
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -27,7 +27,7 @@ setup(
|
|||||||
'setuptools',
|
'setuptools',
|
||||||
'Mopidy >= 0.18',
|
'Mopidy >= 0.18',
|
||||||
'Pykka >= 1.1',
|
'Pykka >= 1.1',
|
||||||
'pygame'
|
'pygame'
|
||||||
],
|
],
|
||||||
test_suite='nose.collector',
|
test_suite='nose.collector',
|
||||||
tests_require=[
|
tests_require=[
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from mopidy_touchscreen import Extension, touch_screen as frontend_lib
|
|||||||
|
|
||||||
|
|
||||||
class ExtensionTest(unittest.TestCase):
|
class ExtensionTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_get_default_config(self):
|
def test_get_default_config(self):
|
||||||
ext = Extension()
|
ext = Extension()
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ class ExtensionTest(unittest.TestCase):
|
|||||||
schema = ext.get_config_schema()
|
schema = ext.get_config_schema()
|
||||||
|
|
||||||
# TODO Test the content of your config schema
|
# TODO Test the content of your config schema
|
||||||
# self.assertIn('username', schema)
|
#self.assertIn('username', schema)
|
||||||
#self.assertIn('password', schema)
|
#self.assertIn('password', schema)
|
||||||
|
|
||||||
# TODO Write more tests
|
# TODO Write more tests
|
||||||
|
|||||||
Reference in New Issue
Block a user