1+ # The MIT License (MIT)
2+ #
3+ # Copyright (c) 2019 Matt Land
4+ #
5+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6+ # of this software and associated documentation files (the "Software"), to deal
7+ # in the Software without restriction, including without limitation the rights
8+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+ # copies of the Software, and to permit persons to whom the Software is
10+ # furnished to do so, subject to the following conditions:
11+ #
12+ # The above copyright notice and this permission notice shall be included in
13+ # all copies or substantial portions of the Software.
14+ #
15+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+ # THE SOFTWARE.
122"""
23+ `adafruit_imageload.tests.displayio_shared_bindings`
24+ ====================================================
25+
226The classes in this file are designed to emulate Circuitpython's displayio classes
327for Bitmap and Palette. These mimic classes should have the same methods and interface as the real interface,
428but with extra validation checks, warnings, and messages to facilitate debugging.
731 working correctly on hardware running Circuitpython, but without needing to upload code to a board
832 after each attempt.
933
34+ * Author(s): Matt Land
35+
1036"""
37+ from typing import Union
1138
1239
1340class Bitmap_C_Interface (object ):
1441 """
15- Simulates the displayio.Bitmap class for testing
42+ A class to simulate the displayio.Bitmap class for testing, based on
43+ https://circuitpython.readthedocs.io/en/latest/shared-bindings/displayio/Bitmap.html
44+ In case of discrepancy, the C implementation takes precedence.
1645 """
1746
18- def __init__ (self , width , height , colors ) :
47+ def __init__ (self , width : int , height : int , colors : int ) -> None :
1948 self .width = width
2049 self .height = height
2150 self .colors = colors
@@ -31,9 +60,15 @@ def _abs_pos(self, width: int, height: int) -> int:
3160 def _decode (self , position : int ) -> tuple :
3261 return position % self .width , position // self .width
3362
34- def __setitem__ (self , key : tuple , value : int ):
63+ def __setitem__ (self , key : Union [tuple , int ], value : int ) -> None :
64+ """
65+ Set using x, y coordinates, or absolution position
66+ bitmap[0] = 1
67+ bitmap[2,1] = 5
68+ """
3569 if isinstance (key , tuple ):
36- # order is X, Y from the docs https://github.com/adafruit/circuitpython/blob/master/shared-bindings/displayio/Bitmap.c
70+ # order is X, Y from the docs
71+ # https://github.com/adafruit/circuitpython/blob/master/shared-bindings/displayio/Bitmap.c
3772 self .__setitem__ (self ._abs_pos (key [0 ], key [1 ]), value )
3873 return
3974 if not isinstance (value , (int )):
@@ -42,7 +77,7 @@ def __setitem__(self, key: tuple, value: int):
4277 raise ValueError (f"pixel value { value } too large" )
4378 self .data [key ] = value
4479
45- def __getitem__ (self , item : tuple ) -> bytearray :
80+ def __getitem__ (self , item : Union [ tuple , int ] ) -> bytearray :
4681 if isinstance (item , tuple ):
4782 return self .__getitem__ (self ._abs_pos (item [0 ], item [1 ]))
4883 if item > self .height * self .width :
@@ -52,7 +87,11 @@ def __getitem__(self, item: tuple) -> bytearray:
5287 except KeyError :
5388 raise RuntimeError ("no data at {} [{}]" .format (self ._decode (item ), item ))
5489
55- def validate (self ):
90+ def validate (self ) -> None :
91+ """
92+ method to to make sure all pixels allocated in the Bitmap
93+ were set with a value
94+ """
5695 if not self .data :
5796 raise ValueError ("no rows were set / no data in memory" )
5897 for i in range (self .height * self .width , 0 ):
@@ -61,7 +100,18 @@ def validate(self):
61100 except KeyError :
62101 raise ValueError ("missing data at {i}" )
63102
64- def __str__ (self ):
103+ def __str__ (self ) -> str :
104+ """
105+ method to dump the contents of the Bitmap to a terminal,
106+ for debugging purposes
107+
108+ Example:
109+ --------
110+
111+ bitmap = Bitmap(5, 4, 4)
112+ ... # assign bitmap values
113+ print(str(bitmap))
114+ """
65115 out = "\n "
66116 for y in range (self .height ):
67117 for x in range (self .width ):
@@ -73,29 +123,41 @@ def __str__(self):
73123
74124class Palette_C_Interface (object ):
75125 """
76- Simulates the displayio.Palette class for testing
126+ A class to simulates the displayio.Palette class for testing, based on
127+ https://circuitpython.readthedocs.io/en/latest/shared-bindings/displayio/Palette.html
128+ In case of discrepancy, the C implementation takes precedence.
77129 """
78130
79- def __init__ (self , num_colors ) :
131+ def __init__ (self , num_colors : int ) -> None :
80132 self .num_colors = num_colors
81133 self .colors = {}
82134
83- def __setitem__ (self , key , value ):
135+ def __setitem__ (self , key : int , value : Union [bytes , int , bytearray ]) -> None :
136+ """
137+ Set using zero indexed color value
138+ palette = Palette(1)
139+ palette[0] = 0xFFFFFF
140+
141+ """
84142 if key >= self .num_colors :
85143 raise ValueError (
86144 f"palette index { key } is greater than allowed by num_colors { self .num_colors } "
87145 )
88- if not isinstance (value , (bytes , int )):
146+ if not isinstance (value , (bytes , int , bytearray )):
89147 raise ValueError (f"palette color should be bytes, not { type (value )} " )
90- if isinstance (value , int ) and value > 255 :
148+ if isinstance (value , int ) and value > 0xFFFFFF :
91149 raise ValueError (f"palette color int { value } is too large" )
92150 if self .colors .get (key ):
93151 raise ValueError (
94152 f"palette color { key } was already set, should not reassign"
95153 )
96154 self .colors [key ] = value
97155
98- def __getitem__ (self , item ):
156+ def __getitem__ (self , item : int ) -> Union [bytes , int , bytearray ]:
157+ """
158+ Warning: this method is not supported in the actual C interface.
159+ It is provided here for debugging purposes.
160+ """
99161 if item >= self .num_colors :
100162 raise ValueError (
101163 f"palette index { item } should be less than { self .num_colors } "
@@ -105,17 +167,35 @@ def __getitem__(self, item):
105167 return self .colors [item ]
106168
107169 def validate (self ):
170+ """
171+ method to make sure all colors allocated in Palette were set to a value
172+ """
108173 if not self .colors :
109- raise ValueError ("no palette colors were set" )
110- if len (self .colors ) > self .num_colors :
111- raise ValueError ("too many colors inserted into palette" )
174+ raise IndexError ("no palette colors were set" )
175+ if len (self .colors ) != self .num_colors :
176+ raise IndexError (
177+ "palette was initialized for {} colors, but only {} were inserted" .format (
178+ self .num_colors , len (self .colors )
179+ )
180+ )
112181 for i in range (self .num_colors ):
113182 try :
114183 self .colors
115184 except IndexError :
116185 raise ValueError ("missing color `{}` in palette color list" .format (i ))
117186
118187 def __str__ (self ):
188+ """
189+ method to dump the contents of the Palette to a terminal,
190+ for debugging purposes
191+
192+ Example:
193+ --------
194+
195+ palette = Palette(1)
196+ palette[0] = 0xFFFFFF
197+ print(str(palette))
198+ """
119199 out = "\n Palette:\n "
120200 for y in range (len (self .colors )):
121201 out += f" [{ y } ] { self .colors [y ]} \n "
0 commit comments