We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
dynamo query with hash key returns wrong results
When executing a query in dynamodb wrong result is returned

Step to reproduce:
add an insert to the default query_test in the unit tests:

```
@mock_dynamodb
def test_query():
    conn = boto.connect_dynamodb()
    table = create_table(conn)

    item_data = {
        'Body': 'http://url_to_lolcat.gif',
        'SentBy': 'User A',
        'ReceivedTime': '12/9/2011 11:36:03 PM',
    }
    # the extra item
    item = table.new_item(
        hash_key='the-key1',
        range_key='4561',
        attrs=item_data,
    )
    item.put()

    item = table.new_item(
        hash_key='the-key',
        range_key='456',
        attrs=item_data,
    )
    item.put()

    item = table.new_item(
        hash_key='the-key',
        range_key='123',
        attrs=item_data,
    )
    item.put()

    item = table.new_item(
        hash_key='the-key',
        range_key='789',
        attrs=item_data,
    )
    item.put()

    results = table.query(hash_key='the-key', range_key_condition=condition.GT('1'))
    results.response['Items'].should.have.length_of(3)
```

This new test will fail as the library will return 4 results in stead of 3


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `moto/dynamodb/models.py`
Content:
```
1 from collections import defaultdict
2 import datetime
3 import json
4 
5 try:
6     from collections import OrderedDict
7 except ImportError:
8     # python 2.6 or earlier, use backport
9     from ordereddict import OrderedDict
10 
11 
12 from moto.core import BaseBackend
13 from .comparisons import get_comparison_func
14 from .utils import unix_time
15 
16 
17 class DynamoJsonEncoder(json.JSONEncoder):
18     def default(self, obj):
19         if hasattr(obj, 'to_json'):
20             return obj.to_json()
21 
22 
23 def dynamo_json_dump(dynamo_object):
24     return json.dumps(dynamo_object, cls=DynamoJsonEncoder)
25 
26 
27 class DynamoType(object):
28     """
29     http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataModel.html#DataModelDataTypes
30     """
31 
32     def __init__(self, type_as_dict):
33         self.type = type_as_dict.keys()[0]
34         self.value = type_as_dict.values()[0]
35 
36     def __hash__(self):
37         return hash((self.type, self.value))
38 
39     def __eq__(self, other):
40         return (
41             self.type == other.type and
42             self.value == other.value
43         )
44 
45     def __repr__(self):
46         return "DynamoType: {0}".format(self.to_json())
47 
48     def to_json(self):
49         return {self.type: self.value}
50 
51     def compare(self, range_comparison, range_objs):
52         """
53         Compares this type against comparison filters
54         """
55         range_values = [obj.value for obj in range_objs]
56         comparison_func = get_comparison_func(range_comparison)
57         return comparison_func(self.value, *range_values)
58 
59 
60 class Item(object):
61     def __init__(self, hash_key, hash_key_type, range_key, range_key_type, attrs):
62         self.hash_key = hash_key
63         self.hash_key_type = hash_key_type
64         self.range_key = range_key
65         self.range_key_type = range_key_type
66 
67         self.attrs = {}
68         for key, value in attrs.iteritems():
69             self.attrs[key] = DynamoType(value)
70 
71     def __repr__(self):
72         return "Item: {0}".format(self.to_json())
73 
74     def to_json(self):
75         attributes = {}
76         for attribute_key, attribute in self.attrs.iteritems():
77             attributes[attribute_key] = attribute.value
78 
79         return {
80             "Attributes": attributes
81         }
82 
83     def describe_attrs(self, attributes):
84         if attributes:
85             included = {}
86             for key, value in self.attrs.iteritems():
87                 if key in attributes:
88                     included[key] = value
89         else:
90             included = self.attrs
91         return {
92             "Item": included
93         }
94 
95 
96 class Table(object):
97 
98     def __init__(self, name, hash_key_attr, hash_key_type,
99                  range_key_attr=None, range_key_type=None, read_capacity=None,
100                  write_capacity=None):
101         self.name = name
102         self.hash_key_attr = hash_key_attr
103         self.hash_key_type = hash_key_type
104         self.range_key_attr = range_key_attr
105         self.range_key_type = range_key_type
106         self.read_capacity = read_capacity
107         self.write_capacity = write_capacity
108         self.created_at = datetime.datetime.now()
109         self.items = defaultdict(dict)
110 
111     @property
112     def has_range_key(self):
113         return self.range_key_attr is not None
114 
115     @property
116     def describe(self):
117         results = {
118             "Table": {
119                 "CreationDateTime": unix_time(self.created_at),
120                 "KeySchema": {
121                     "HashKeyElement": {
122                         "AttributeName": self.hash_key_attr,
123                         "AttributeType": self.hash_key_type
124                     },
125                 },
126                 "ProvisionedThroughput": {
127                     "ReadCapacityUnits": self.read_capacity,
128                     "WriteCapacityUnits": self.write_capacity
129                 },
130                 "TableName": self.name,
131                 "TableStatus": "ACTIVE",
132                 "ItemCount": len(self),
133                 "TableSizeBytes": 0,
134             }
135         }
136         if self.has_range_key:
137             results["Table"]["KeySchema"]["RangeKeyElement"] = {
138                 "AttributeName": self.range_key_attr,
139                 "AttributeType": self.range_key_type
140             }
141         return results
142 
143     def __len__(self):
144         count = 0
145         for key, value in self.items.iteritems():
146             if self.has_range_key:
147                 count += len(value)
148             else:
149                 count += 1
150         return count
151 
152     def __nonzero__(self):
153         return True
154 
155     def put_item(self, item_attrs):
156         hash_value = DynamoType(item_attrs.get(self.hash_key_attr))
157         if self.has_range_key:
158             range_value = DynamoType(item_attrs.get(self.range_key_attr))
159         else:
160             range_value = None
161 
162         item = Item(hash_value, self.hash_key_type, range_value, self.range_key_type, item_attrs)
163 
164         if range_value:
165             self.items[hash_value][range_value] = item
166         else:
167             self.items[hash_value] = item
168         return item
169 
170     def get_item(self, hash_key, range_key):
171         if self.has_range_key and not range_key:
172             raise ValueError("Table has a range key, but no range key was passed into get_item")
173         try:
174             if range_key:
175                 return self.items[hash_key][range_key]
176             else:
177                 return self.items[hash_key]
178         except KeyError:
179             return None
180 
181     def query(self, hash_key, range_comparison, range_objs):
182         results = []
183         last_page = True  # Once pagination is implemented, change this
184 
185         possible_results = list(self.all_items())
186         if range_comparison:
187             for result in possible_results:
188                 if result.range_key.compare(range_comparison, range_objs):
189                     results.append(result)
190         else:
191             # If we're not filtering on range key, return all values
192             results = possible_results
193         return results, last_page
194 
195     def all_items(self):
196         for hash_set in self.items.values():
197             if self.range_key_attr:
198                 for item in hash_set.values():
199                     yield item
200             else:
201                 yield hash_set
202 
203     def scan(self, filters):
204         results = []
205         scanned_count = 0
206         last_page = True  # Once pagination is implemented, change this
207 
208         for result in self.all_items():
209             scanned_count += 1
210             passes_all_conditions = True
211             for attribute_name, (comparison_operator, comparison_objs) in filters.iteritems():
212                 attribute = result.attrs.get(attribute_name)
213 
214                 if attribute:
215                     # Attribute found
216                     if not attribute.compare(comparison_operator, comparison_objs):
217                         passes_all_conditions = False
218                         break
219                 elif comparison_operator == 'NULL':
220                     # Comparison is NULL and we don't have the attribute
221                     continue
222                 else:
223                     # No attribute found and comparison is no NULL. This item fails
224                     passes_all_conditions = False
225                     break
226 
227             if passes_all_conditions:
228                 results.append(result)
229 
230         return results, scanned_count, last_page
231 
232     def delete_item(self, hash_key, range_key):
233         try:
234             if range_key:
235                 return self.items[hash_key].pop(range_key)
236             else:
237                 return self.items.pop(hash_key)
238         except KeyError:
239             return None
240 
241 
242 class DynamoDBBackend(BaseBackend):
243 
244     def __init__(self):
245         self.tables = OrderedDict()
246 
247     def create_table(self, name, **params):
248         table = Table(name, **params)
249         self.tables[name] = table
250         return table
251 
252     def delete_table(self, name):
253         return self.tables.pop(name, None)
254 
255     def update_table_throughput(self, name, new_read_units, new_write_units):
256         table = self.tables[name]
257         table.read_capacity = new_read_units
258         table.write_capacity = new_write_units
259         return table
260 
261     def put_item(self, table_name, item_attrs):
262         table = self.tables.get(table_name)
263         if not table:
264             return None
265 
266         return table.put_item(item_attrs)
267 
268     def get_item(self, table_name, hash_key_dict, range_key_dict):
269         table = self.tables.get(table_name)
270         if not table:
271             return None
272 
273         hash_key = DynamoType(hash_key_dict)
274         range_key = DynamoType(range_key_dict) if range_key_dict else None
275 
276         return table.get_item(hash_key, range_key)
277 
278     def query(self, table_name, hash_key_dict, range_comparison, range_value_dicts):
279         table = self.tables.get(table_name)
280         if not table:
281             return None, None
282 
283         hash_key = DynamoType(hash_key_dict)
284         range_values = [DynamoType(range_value) for range_value in range_value_dicts]
285 
286         return table.query(hash_key, range_comparison, range_values)
287 
288     def scan(self, table_name, filters):
289         table = self.tables.get(table_name)
290         if not table:
291             return None, None, None
292 
293         scan_filters = {}
294         for key, (comparison_operator, comparison_values) in filters.iteritems():
295             dynamo_types = [DynamoType(value) for value in comparison_values]
296             scan_filters[key] = (comparison_operator, dynamo_types)
297 
298         return table.scan(scan_filters)
299 
300     def delete_item(self, table_name, hash_key_dict, range_key_dict):
301         table = self.tables.get(table_name)
302         if not table:
303             return None
304 
305         hash_key = DynamoType(hash_key_dict)
306         range_key = DynamoType(range_key_dict) if range_key_dict else None
307 
308         return table.delete_item(hash_key, range_key)
309 
310 
311 dynamodb_backend = DynamoDBBackend()
312
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/moto/dynamodb/models.py b/moto/dynamodb/models.py
--- a/moto/dynamodb/models.py
+++ b/moto/dynamodb/models.py
@@ -182,7 +182,11 @@
         results = []
         last_page = True  # Once pagination is implemented, change this
 
-        possible_results = list(self.all_items())
+        if self.range_key_attr:
+            possible_results = self.items[hash_key].values()
+        else:
+            possible_results = list(self.all_items())
+
         if range_comparison:
             for result in possible_results:
                 if result.range_key.compare(range_comparison, range_objs):

{"golden_diff": "diff --git a/moto/dynamodb/models.py b/moto/dynamodb/models.py\n--- a/moto/dynamodb/models.py\n+++ b/moto/dynamodb/models.py\n@@ -182,7 +182,11 @@\n         results = []\n         last_page = True  # Once pagination is implemented, change this\n \n-        possible_results = list(self.all_items())\n+        if self.range_key_attr:\n+            possible_results = self.items[hash_key].values()\n+        else:\n+            possible_results = list(self.all_items())\n+\n         if range_comparison:\n             for result in possible_results:\n                 if result.range_key.compare(range_comparison, range_objs):\n", "issue": "dynamo query with hash key returns wrong results\nWhen executing a query in dynamodb wrong result is returned\n\nStep to reproduce:\nadd an insert to the default query_test in the unit tests:\n\n```\n@mock_dynamodb\ndef test_query():\n    conn = boto.connect_dynamodb()\n    table = create_table(conn)\n\n    item_data = {\n        'Body': 'http://url_to_lolcat.gif',\n        'SentBy': 'User A',\n        'ReceivedTime': '12/9/2011 11:36:03 PM',\n    }\n    # the extra item\n    item = table.new_item(\n        hash_key='the-key1',\n        range_key='4561',\n        attrs=item_data,\n    )\n    item.put()\n\n    item = table.new_item(\n        hash_key='the-key',\n        range_key='456',\n        attrs=item_data,\n    )\n    item.put()\n\n    item = table.new_item(\n        hash_key='the-key',\n        range_key='123',\n        attrs=item_data,\n    )\n    item.put()\n\n    item = table.new_item(\n        hash_key='the-key',\n        range_key='789',\n        attrs=item_data,\n    )\n    item.put()\n\n    results = table.query(hash_key='the-key', range_key_condition=condition.GT('1'))\n    results.response['Items'].should.have.length_of(3)\n```\n\nThis new test will fail as the library will return 4 results in stead of 3\n\n", "before_files": [{"content": "from collections import defaultdict\nimport datetime\nimport json\n\ntry:\n    from collections import OrderedDict\nexcept ImportError:\n    # python 2.6 or earlier, use backport\n    from ordereddict import OrderedDict\n\n\nfrom moto.core import BaseBackend\nfrom .comparisons import get_comparison_func\nfrom .utils import unix_time\n\n\nclass DynamoJsonEncoder(json.JSONEncoder):\n    def default(self, obj):\n        if hasattr(obj, 'to_json'):\n            return obj.to_json()\n\n\ndef dynamo_json_dump(dynamo_object):\n    return json.dumps(dynamo_object, cls=DynamoJsonEncoder)\n\n\nclass DynamoType(object):\n    \"\"\"\n    http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataModel.html#DataModelDataTypes\n    \"\"\"\n\n    def __init__(self, type_as_dict):\n        self.type = type_as_dict.keys()[0]\n        self.value = type_as_dict.values()[0]\n\n    def __hash__(self):\n        return hash((self.type, self.value))\n\n    def __eq__(self, other):\n        return (\n            self.type == other.type and\n            self.value == other.value\n        )\n\n    def __repr__(self):\n        return \"DynamoType: {0}\".format(self.to_json())\n\n    def to_json(self):\n        return {self.type: self.value}\n\n    def compare(self, range_comparison, range_objs):\n        \"\"\"\n        Compares this type against comparison filters\n        \"\"\"\n        range_values = [obj.value for obj in range_objs]\n        comparison_func = get_comparison_func(range_comparison)\n        return comparison_func(self.value, *range_values)\n\n\nclass Item(object):\n    def __init__(self, hash_key, hash_key_type, range_key, range_key_type, attrs):\n        self.hash_key = hash_key\n        self.hash_key_type = hash_key_type\n        self.range_key = range_key\n        self.range_key_type = range_key_type\n\n        self.attrs = {}\n        for key, value in attrs.iteritems():\n            self.attrs[key] = DynamoType(value)\n\n    def __repr__(self):\n        return \"Item: {0}\".format(self.to_json())\n\n    def to_json(self):\n        attributes = {}\n        for attribute_key, attribute in self.attrs.iteritems():\n            attributes[attribute_key] = attribute.value\n\n        return {\n            \"Attributes\": attributes\n        }\n\n    def describe_attrs(self, attributes):\n        if attributes:\n            included = {}\n            for key, value in self.attrs.iteritems():\n                if key in attributes:\n                    included[key] = value\n        else:\n            included = self.attrs\n        return {\n            \"Item\": included\n        }\n\n\nclass Table(object):\n\n    def __init__(self, name, hash_key_attr, hash_key_type,\n                 range_key_attr=None, range_key_type=None, read_capacity=None,\n                 write_capacity=None):\n        self.name = name\n        self.hash_key_attr = hash_key_attr\n        self.hash_key_type = hash_key_type\n        self.range_key_attr = range_key_attr\n        self.range_key_type = range_key_type\n        self.read_capacity = read_capacity\n        self.write_capacity = write_capacity\n        self.created_at = datetime.datetime.now()\n        self.items = defaultdict(dict)\n\n    @property\n    def has_range_key(self):\n        return self.range_key_attr is not None\n\n    @property\n    def describe(self):\n        results = {\n            \"Table\": {\n                \"CreationDateTime\": unix_time(self.created_at),\n                \"KeySchema\": {\n                    \"HashKeyElement\": {\n                        \"AttributeName\": self.hash_key_attr,\n                        \"AttributeType\": self.hash_key_type\n                    },\n                },\n                \"ProvisionedThroughput\": {\n                    \"ReadCapacityUnits\": self.read_capacity,\n                    \"WriteCapacityUnits\": self.write_capacity\n                },\n                \"TableName\": self.name,\n                \"TableStatus\": \"ACTIVE\",\n                \"ItemCount\": len(self),\n                \"TableSizeBytes\": 0,\n            }\n        }\n        if self.has_range_key:\n            results[\"Table\"][\"KeySchema\"][\"RangeKeyElement\"] = {\n                \"AttributeName\": self.range_key_attr,\n                \"AttributeType\": self.range_key_type\n            }\n        return results\n\n    def __len__(self):\n        count = 0\n        for key, value in self.items.iteritems():\n            if self.has_range_key:\n                count += len(value)\n            else:\n                count += 1\n        return count\n\n    def __nonzero__(self):\n        return True\n\n    def put_item(self, item_attrs):\n        hash_value = DynamoType(item_attrs.get(self.hash_key_attr))\n        if self.has_range_key:\n            range_value = DynamoType(item_attrs.get(self.range_key_attr))\n        else:\n            range_value = None\n\n        item = Item(hash_value, self.hash_key_type, range_value, self.range_key_type, item_attrs)\n\n        if range_value:\n            self.items[hash_value][range_value] = item\n        else:\n            self.items[hash_value] = item\n        return item\n\n    def get_item(self, hash_key, range_key):\n        if self.has_range_key and not range_key:\n            raise ValueError(\"Table has a range key, but no range key was passed into get_item\")\n        try:\n            if range_key:\n                return self.items[hash_key][range_key]\n            else:\n                return self.items[hash_key]\n        except KeyError:\n            return None\n\n    def query(self, hash_key, range_comparison, range_objs):\n        results = []\n        last_page = True  # Once pagination is implemented, change this\n\n        possible_results = list(self.all_items())\n        if range_comparison:\n            for result in possible_results:\n                if result.range_key.compare(range_comparison, range_objs):\n                    results.append(result)\n        else:\n            # If we're not filtering on range key, return all values\n            results = possible_results\n        return results, last_page\n\n    def all_items(self):\n        for hash_set in self.items.values():\n            if self.range_key_attr:\n                for item in hash_set.values():\n                    yield item\n            else:\n                yield hash_set\n\n    def scan(self, filters):\n        results = []\n        scanned_count = 0\n        last_page = True  # Once pagination is implemented, change this\n\n        for result in self.all_items():\n            scanned_count += 1\n            passes_all_conditions = True\n            for attribute_name, (comparison_operator, comparison_objs) in filters.iteritems():\n                attribute = result.attrs.get(attribute_name)\n\n                if attribute:\n                    # Attribute found\n                    if not attribute.compare(comparison_operator, comparison_objs):\n                        passes_all_conditions = False\n                        break\n                elif comparison_operator == 'NULL':\n                    # Comparison is NULL and we don't have the attribute\n                    continue\n                else:\n                    # No attribute found and comparison is no NULL. This item fails\n                    passes_all_conditions = False\n                    break\n\n            if passes_all_conditions:\n                results.append(result)\n\n        return results, scanned_count, last_page\n\n    def delete_item(self, hash_key, range_key):\n        try:\n            if range_key:\n                return self.items[hash_key].pop(range_key)\n            else:\n                return self.items.pop(hash_key)\n        except KeyError:\n            return None\n\n\nclass DynamoDBBackend(BaseBackend):\n\n    def __init__(self):\n        self.tables = OrderedDict()\n\n    def create_table(self, name, **params):\n        table = Table(name, **params)\n        self.tables[name] = table\n        return table\n\n    def delete_table(self, name):\n        return self.tables.pop(name, None)\n\n    def update_table_throughput(self, name, new_read_units, new_write_units):\n        table = self.tables[name]\n        table.read_capacity = new_read_units\n        table.write_capacity = new_write_units\n        return table\n\n    def put_item(self, table_name, item_attrs):\n        table = self.tables.get(table_name)\n        if not table:\n            return None\n\n        return table.put_item(item_attrs)\n\n    def get_item(self, table_name, hash_key_dict, range_key_dict):\n        table = self.tables.get(table_name)\n        if not table:\n            return None\n\n        hash_key = DynamoType(hash_key_dict)\n        range_key = DynamoType(range_key_dict) if range_key_dict else None\n\n        return table.get_item(hash_key, range_key)\n\n    def query(self, table_name, hash_key_dict, range_comparison, range_value_dicts):\n        table = self.tables.get(table_name)\n        if not table:\n            return None, None\n\n        hash_key = DynamoType(hash_key_dict)\n        range_values = [DynamoType(range_value) for range_value in range_value_dicts]\n\n        return table.query(hash_key, range_comparison, range_values)\n\n    def scan(self, table_name, filters):\n        table = self.tables.get(table_name)\n        if not table:\n            return None, None, None\n\n        scan_filters = {}\n        for key, (comparison_operator, comparison_values) in filters.iteritems():\n            dynamo_types = [DynamoType(value) for value in comparison_values]\n            scan_filters[key] = (comparison_operator, dynamo_types)\n\n        return table.scan(scan_filters)\n\n    def delete_item(self, table_name, hash_key_dict, range_key_dict):\n        table = self.tables.get(table_name)\n        if not table:\n            return None\n\n        hash_key = DynamoType(hash_key_dict)\n        range_key = DynamoType(range_key_dict) if range_key_dict else None\n\n        return table.delete_item(hash_key, range_key)\n\n\ndynamodb_backend = DynamoDBBackend()\n", "path": "moto/dynamodb/models.py"}], "after_files": [{"content": "from collections import defaultdict\nimport datetime\nimport json\n\ntry:\n    from collections import OrderedDict\nexcept ImportError:\n    # python 2.6 or earlier, use backport\n    from ordereddict import OrderedDict\n\n\nfrom moto.core import BaseBackend\nfrom .comparisons import get_comparison_func\nfrom .utils import unix_time\n\n\nclass DynamoJsonEncoder(json.JSONEncoder):\n    def default(self, obj):\n        if hasattr(obj, 'to_json'):\n            return obj.to_json()\n\n\ndef dynamo_json_dump(dynamo_object):\n    return json.dumps(dynamo_object, cls=DynamoJsonEncoder)\n\n\nclass DynamoType(object):\n    \"\"\"\n    http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataModel.html#DataModelDataTypes\n    \"\"\"\n\n    def __init__(self, type_as_dict):\n        self.type = type_as_dict.keys()[0]\n        self.value = type_as_dict.values()[0]\n\n    def __hash__(self):\n        return hash((self.type, self.value))\n\n    def __eq__(self, other):\n        return (\n            self.type == other.type and\n            self.value == other.value\n        )\n\n    def __repr__(self):\n        return \"DynamoType: {0}\".format(self.to_json())\n\n    def to_json(self):\n        return {self.type: self.value}\n\n    def compare(self, range_comparison, range_objs):\n        \"\"\"\n        Compares this type against comparison filters\n        \"\"\"\n        range_values = [obj.value for obj in range_objs]\n        comparison_func = get_comparison_func(range_comparison)\n        return comparison_func(self.value, *range_values)\n\n\nclass Item(object):\n    def __init__(self, hash_key, hash_key_type, range_key, range_key_type, attrs):\n        self.hash_key = hash_key\n        self.hash_key_type = hash_key_type\n        self.range_key = range_key\n        self.range_key_type = range_key_type\n\n        self.attrs = {}\n        for key, value in attrs.iteritems():\n            self.attrs[key] = DynamoType(value)\n\n    def __repr__(self):\n        return \"Item: {0}\".format(self.to_json())\n\n    def to_json(self):\n        attributes = {}\n        for attribute_key, attribute in self.attrs.iteritems():\n            attributes[attribute_key] = attribute.value\n\n        return {\n            \"Attributes\": attributes\n        }\n\n    def describe_attrs(self, attributes):\n        if attributes:\n            included = {}\n            for key, value in self.attrs.iteritems():\n                if key in attributes:\n                    included[key] = value\n        else:\n            included = self.attrs\n        return {\n            \"Item\": included\n        }\n\n\nclass Table(object):\n\n    def __init__(self, name, hash_key_attr, hash_key_type,\n                 range_key_attr=None, range_key_type=None, read_capacity=None,\n                 write_capacity=None):\n        self.name = name\n        self.hash_key_attr = hash_key_attr\n        self.hash_key_type = hash_key_type\n        self.range_key_attr = range_key_attr\n        self.range_key_type = range_key_type\n        self.read_capacity = read_capacity\n        self.write_capacity = write_capacity\n        self.created_at = datetime.datetime.now()\n        self.items = defaultdict(dict)\n\n    @property\n    def has_range_key(self):\n        return self.range_key_attr is not None\n\n    @property\n    def describe(self):\n        results = {\n            \"Table\": {\n                \"CreationDateTime\": unix_time(self.created_at),\n                \"KeySchema\": {\n                    \"HashKeyElement\": {\n                        \"AttributeName\": self.hash_key_attr,\n                        \"AttributeType\": self.hash_key_type\n                    },\n                },\n                \"ProvisionedThroughput\": {\n                    \"ReadCapacityUnits\": self.read_capacity,\n                    \"WriteCapacityUnits\": self.write_capacity\n                },\n                \"TableName\": self.name,\n                \"TableStatus\": \"ACTIVE\",\n                \"ItemCount\": len(self),\n                \"TableSizeBytes\": 0,\n            }\n        }\n        if self.has_range_key:\n            results[\"Table\"][\"KeySchema\"][\"RangeKeyElement\"] = {\n                \"AttributeName\": self.range_key_attr,\n                \"AttributeType\": self.range_key_type\n            }\n        return results\n\n    def __len__(self):\n        count = 0\n        for key, value in self.items.iteritems():\n            if self.has_range_key:\n                count += len(value)\n            else:\n                count += 1\n        return count\n\n    def __nonzero__(self):\n        return True\n\n    def put_item(self, item_attrs):\n        hash_value = DynamoType(item_attrs.get(self.hash_key_attr))\n        if self.has_range_key:\n            range_value = DynamoType(item_attrs.get(self.range_key_attr))\n        else:\n            range_value = None\n\n        item = Item(hash_value, self.hash_key_type, range_value, self.range_key_type, item_attrs)\n\n        if range_value:\n            self.items[hash_value][range_value] = item\n        else:\n            self.items[hash_value] = item\n        return item\n\n    def get_item(self, hash_key, range_key):\n        if self.has_range_key and not range_key:\n            raise ValueError(\"Table has a range key, but no range key was passed into get_item\")\n        try:\n            if range_key:\n                return self.items[hash_key][range_key]\n            else:\n                return self.items[hash_key]\n        except KeyError:\n            return None\n\n    def query(self, hash_key, range_comparison, range_objs):\n        results = []\n        last_page = True  # Once pagination is implemented, change this\n\n        if self.range_key_attr:\n            possible_results = self.items[hash_key].values()\n        else:\n            possible_results = list(self.all_items())\n\n        if range_comparison:\n            for result in possible_results:\n                if result.range_key.compare(range_comparison, range_objs):\n                    results.append(result)\n        else:\n            # If we're not filtering on range key, return all values\n            results = possible_results\n        return results, last_page\n\n    def all_items(self):\n        for hash_set in self.items.values():\n            if self.range_key_attr:\n                for item in hash_set.values():\n                    yield item\n            else:\n                yield hash_set\n\n    def scan(self, filters):\n        results = []\n        scanned_count = 0\n        last_page = True  # Once pagination is implemented, change this\n\n        for result in self.all_items():\n            scanned_count += 1\n            passes_all_conditions = True\n            for attribute_name, (comparison_operator, comparison_objs) in filters.iteritems():\n                attribute = result.attrs.get(attribute_name)\n\n                if attribute:\n                    # Attribute found\n                    if not attribute.compare(comparison_operator, comparison_objs):\n                        passes_all_conditions = False\n                        break\n                elif comparison_operator == 'NULL':\n                    # Comparison is NULL and we don't have the attribute\n                    continue\n                else:\n                    # No attribute found and comparison is no NULL. This item fails\n                    passes_all_conditions = False\n                    break\n\n            if passes_all_conditions:\n                results.append(result)\n\n        return results, scanned_count, last_page\n\n    def delete_item(self, hash_key, range_key):\n        try:\n            if range_key:\n                return self.items[hash_key].pop(range_key)\n            else:\n                return self.items.pop(hash_key)\n        except KeyError:\n            return None\n\n\nclass DynamoDBBackend(BaseBackend):\n\n    def __init__(self):\n        self.tables = OrderedDict()\n\n    def create_table(self, name, **params):\n        table = Table(name, **params)\n        self.tables[name] = table\n        return table\n\n    def delete_table(self, name):\n        return self.tables.pop(name, None)\n\n    def update_table_throughput(self, name, new_read_units, new_write_units):\n        table = self.tables[name]\n        table.read_capacity = new_read_units\n        table.write_capacity = new_write_units\n        return table\n\n    def put_item(self, table_name, item_attrs):\n        table = self.tables.get(table_name)\n        if not table:\n            return None\n\n        return table.put_item(item_attrs)\n\n    def get_item(self, table_name, hash_key_dict, range_key_dict):\n        table = self.tables.get(table_name)\n        if not table:\n            return None\n\n        hash_key = DynamoType(hash_key_dict)\n        range_key = DynamoType(range_key_dict) if range_key_dict else None\n\n        return table.get_item(hash_key, range_key)\n\n    def query(self, table_name, hash_key_dict, range_comparison, range_value_dicts):\n        table = self.tables.get(table_name)\n        if not table:\n            return None, None\n\n        hash_key = DynamoType(hash_key_dict)\n        range_values = [DynamoType(range_value) for range_value in range_value_dicts]\n\n        return table.query(hash_key, range_comparison, range_values)\n\n    def scan(self, table_name, filters):\n        table = self.tables.get(table_name)\n        if not table:\n            return None, None, None\n\n        scan_filters = {}\n        for key, (comparison_operator, comparison_values) in filters.iteritems():\n            dynamo_types = [DynamoType(value) for value in comparison_values]\n            scan_filters[key] = (comparison_operator, dynamo_types)\n\n        return table.scan(scan_filters)\n\n    def delete_item(self, table_name, hash_key_dict, range_key_dict):\n        table = self.tables.get(table_name)\n        if not table:\n            return None\n\n        hash_key = DynamoType(hash_key_dict)\n        range_key = DynamoType(range_key_dict) if range_key_dict else None\n\n        return table.delete_item(hash_key, range_key)\n\n\ndynamodb_backend = DynamoDBBackend()\n", "path": "moto/dynamodb/models.py"}]}