@@ -1929,9 +1929,8 @@ class ThisKind(model.Model):
19291929 ds_entity = model ._entity_to_ds_entity (entity )
19301930 assert ds_entity ["foo" ] == compressed_value
19311931
1932- @staticmethod
19331932 @pytest .mark .usefixtures ("in_context" )
1934- def test__from_datastore_compressed_repeated_to_compressed ():
1933+ def test__from_datastore_compressed_repeated_to_compressed (self ):
19351934 class ThisKind (model .Model ):
19361935 foo = model .BlobProperty (compressed = True , repeated = True )
19371936
@@ -1955,9 +1954,48 @@ class ThisKind(model.Model):
19551954 ds_entity = model ._entity_to_ds_entity (entity )
19561955 assert ds_entity ["foo" ] == [compressed_value_one , compressed_value_two ]
19571956
1958- @staticmethod
1957+ @pytest .mark .skipif (
1958+ [int (v ) for v in datastore .__version__ .split ("." )] < [2 , 20 , 2 ],
1959+ reason = "uses meanings semantics from datastore v2.20.2 and later" ,
1960+ )
1961+ @pytest .mark .parametrize (
1962+ "meaning" ,
1963+ [
1964+ (model ._MEANING_COMPRESSED , None ), # set root meaning
1965+ (model ._MEANING_COMPRESSED , []),
1966+ (model ._MEANING_COMPRESSED , [1 , 1 ]),
1967+ (None , [model ._MEANING_COMPRESSED ] * 2 ), # set sub-meanings
1968+ ],
1969+ )
19591970 @pytest .mark .usefixtures ("in_context" )
1960- def test__from_datastore_compressed_repeated_to_uncompressed ():
1971+ def test__from_datastore_compressed_repeated_to_compressed_tuple_meaning (
1972+ self , meaning
1973+ ):
1974+ class ThisKind (model .Model ):
1975+ foo = model .BlobProperty (compressed = True , repeated = True )
1976+
1977+ key = datastore .Key ("ThisKind" , 123 , project = "testing" )
1978+ datastore_entity = datastore .Entity (key = key )
1979+ uncompressed_value_one = b"abc" * 1000
1980+ compressed_value_one = zlib .compress (uncompressed_value_one )
1981+ uncompressed_value_two = b"xyz" * 1000
1982+ compressed_value_two = zlib .compress (uncompressed_value_two )
1983+ compressed_value = [compressed_value_one , compressed_value_two ]
1984+ datastore_entity .update ({"foo" : compressed_value })
1985+ meanings = {
1986+ "foo" : (
1987+ meaning ,
1988+ compressed_value ,
1989+ )
1990+ }
1991+ datastore_entity ._meanings = meanings
1992+ protobuf = helpers .entity_to_protobuf (datastore_entity )
1993+ entity = model ._entity_from_protobuf (protobuf )
1994+ ds_entity = model ._entity_to_ds_entity (entity )
1995+ assert ds_entity ["foo" ] == [compressed_value_one , compressed_value_two ]
1996+
1997+ @pytest .mark .usefixtures ("in_context" )
1998+ def test__from_datastore_compressed_repeated_to_uncompressed (self ):
19611999 class ThisKind (model .Model ):
19622000 foo = model .BlobProperty (compressed = False , repeated = True )
19632001
@@ -1981,6 +2019,170 @@ class ThisKind(model.Model):
19812019 ds_entity = model ._entity_to_ds_entity (entity )
19822020 assert ds_entity ["foo" ] == [uncompressed_value_one , uncompressed_value_two ]
19832021
2022+ @pytest .mark .skipif (
2023+ [int (v ) for v in datastore .__version__ .split ("." )] < [2 , 20 , 2 ],
2024+ reason = "uses meanings semantics from datastore v2.20.2 and later" ,
2025+ )
2026+ @pytest .mark .parametrize (
2027+ "meaning" ,
2028+ [
2029+ (model ._MEANING_COMPRESSED , None ), # set root meaning
2030+ (model ._MEANING_COMPRESSED , []),
2031+ (model ._MEANING_COMPRESSED , [1 , 1 ]),
2032+ (None , [model ._MEANING_COMPRESSED ] * 2 ), # set sub-meanings
2033+ ],
2034+ )
2035+ @pytest .mark .usefixtures ("in_context" )
2036+ def test__from_datastore_compressed_repeated_to_uncompressed_tuple_meaning (
2037+ self , meaning
2038+ ):
2039+ class ThisKind (model .Model ):
2040+ foo = model .BlobProperty (compressed = False , repeated = True )
2041+
2042+ key = datastore .Key ("ThisKind" , 123 , project = "testing" )
2043+ datastore_entity = datastore .Entity (key = key )
2044+ uncompressed_value_one = b"abc" * 1000
2045+ compressed_value_one = zlib .compress (uncompressed_value_one )
2046+ uncompressed_value_two = b"xyz" * 1000
2047+ compressed_value_two = zlib .compress (uncompressed_value_two )
2048+ compressed_value = [compressed_value_one , compressed_value_two ]
2049+ datastore_entity .update ({"foo" : compressed_value })
2050+ meanings = {
2051+ "foo" : (
2052+ meaning ,
2053+ compressed_value ,
2054+ )
2055+ }
2056+ datastore_entity ._meanings = meanings
2057+ protobuf = helpers .entity_to_protobuf (datastore_entity )
2058+ entity = model ._entity_from_protobuf (protobuf )
2059+ ds_entity = model ._entity_to_ds_entity (entity )
2060+ assert ds_entity ["foo" ] == [uncompressed_value_one , uncompressed_value_two ]
2061+
2062+ @pytest .mark .skipif (
2063+ [int (v ) for v in datastore .__version__ .split ("." )] < [2 , 20 , 2 ],
2064+ reason = "uses meanings semantics from datastore v2.20.2 and later" ,
2065+ )
2066+ @pytest .mark .parametrize (
2067+ "meaning" ,
2068+ [
2069+ (None , [model ._MEANING_COMPRESSED , None ]),
2070+ (None , [model ._MEANING_COMPRESSED , None , None ]),
2071+ (1 , [model ._MEANING_COMPRESSED , 1 ]),
2072+ (None , [model ._MEANING_COMPRESSED ]),
2073+ ],
2074+ )
2075+ @pytest .mark .usefixtures ("in_context" )
2076+ def test__from_datastore_compressed_repeated_to_uncompressed_mixed_meaning (
2077+ self , meaning
2078+ ):
2079+ """
2080+ One item is compressed, one uncompressed
2081+ """
2082+
2083+ class ThisKind (model .Model ):
2084+ foo = model .BlobProperty (compressed = False , repeated = True )
2085+
2086+ key = datastore .Key ("ThisKind" , 123 , project = "testing" )
2087+ datastore_entity = datastore .Entity (key = key )
2088+ uncompressed_value_one = b"abc" * 1000
2089+ compressed_value_one = zlib .compress (uncompressed_value_one )
2090+ uncompressed_value_two = b"xyz" * 1000
2091+ compressed_value_two = zlib .compress (uncompressed_value_two )
2092+ compressed_value = [compressed_value_one , compressed_value_two ]
2093+ datastore_entity .update ({"foo" : compressed_value })
2094+ meanings = {
2095+ "foo" : (
2096+ meaning ,
2097+ compressed_value ,
2098+ )
2099+ }
2100+ datastore_entity ._meanings = meanings
2101+ protobuf = helpers .entity_to_protobuf (datastore_entity )
2102+ entity = model ._entity_from_protobuf (protobuf )
2103+ ds_entity = model ._entity_to_ds_entity (entity )
2104+ assert ds_entity ["foo" ] == [uncompressed_value_one , compressed_value_two ]
2105+
2106+ @pytest .mark .skipif (
2107+ [int (v ) for v in datastore .__version__ .split ("." )] < [2 , 20 , 2 ],
2108+ reason = "uses meanings semantics from datastore v2.20.2 and later" ,
2109+ )
2110+ @pytest .mark .parametrize (
2111+ "meaning" ,
2112+ [
2113+ (None , None ),
2114+ (None , []),
2115+ (None , [None ]),
2116+ (None , [None , None ]),
2117+ (1 , []),
2118+ (1 , [1 ]),
2119+ (1 , [1 , 1 ]),
2120+ ],
2121+ )
2122+ @pytest .mark .usefixtures ("in_context" )
2123+ def test__from_datastore_compressed_repeated_no_meaning (self , meaning ):
2124+ """
2125+ could be uncompressed, but meaning not set
2126+ """
2127+
2128+ class ThisKind (model .Model ):
2129+ foo = model .BlobProperty (compressed = False , repeated = True )
2130+
2131+ key = datastore .Key ("ThisKind" , 123 , project = "testing" )
2132+ datastore_entity = datastore .Entity (key = key )
2133+ uncompressed_value_one = b"abc" * 1000
2134+ compressed_value_one = zlib .compress (uncompressed_value_one )
2135+ uncompressed_value_two = b"xyz" * 1000
2136+ compressed_value_two = zlib .compress (uncompressed_value_two )
2137+ compressed_value = [compressed_value_one , compressed_value_two ]
2138+ datastore_entity .update ({"foo" : compressed_value })
2139+ meanings = {
2140+ "foo" : (
2141+ meaning ,
2142+ compressed_value ,
2143+ )
2144+ }
2145+ datastore_entity ._meanings = meanings
2146+ protobuf = helpers .entity_to_protobuf (datastore_entity )
2147+ entity = model ._entity_from_protobuf (protobuf )
2148+ ds_entity = model ._entity_to_ds_entity (entity )
2149+ assert ds_entity ["foo" ] == [compressed_value_one , compressed_value_two ]
2150+
2151+ @staticmethod
2152+ @pytest .mark .usefixtures ("in_context" )
2153+ def test__from_datastore_large_value_list ():
2154+ """
2155+ try calling _from_datastore with a meaning list smaller than the value list
2156+ """
2157+
2158+ prop = model .BlobProperty (compressed = False , repeated = True , name = "foo" )
2159+
2160+ key = datastore .Key ("ThisKind" , 123 , project = "testing" )
2161+ datastore_entity = datastore .Entity (key = key )
2162+ uncompressed_value_one = b"abc" * 1000
2163+ compressed_value_one = zlib .compress (uncompressed_value_one )
2164+ uncompressed_value_two = b"xyz" * 1000
2165+ compressed_value_two = zlib .compress (uncompressed_value_two )
2166+ compressed_value = [
2167+ model ._BaseValue (compressed_value_one ),
2168+ model ._BaseValue (compressed_value_two ),
2169+ ]
2170+ datastore_entity .update ({"foo" : compressed_value })
2171+ meanings = {
2172+ "foo" : (
2173+ (None , [model ._MEANING_COMPRESSED ]),
2174+ compressed_value ,
2175+ )
2176+ }
2177+
2178+ datastore_entity ._meanings = meanings
2179+
2180+ updated_value = prop ._from_datastore (datastore_entity , compressed_value )
2181+ assert len (updated_value ) == 2
2182+ assert updated_value [0 ].b_val == uncompressed_value_one
2183+ # second value should remain compressed
2184+ assert updated_value [1 ].b_val == compressed_value_two
2185+
19842186 @staticmethod
19852187 @pytest .mark .usefixtures ("in_context" )
19862188 def test__from_datastore_uncompressed_to_uncompressed ():
0 commit comments