We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ECR `list_images` should return exception when repository does not exist

### Actual
`moto` [will return](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ListImages.html) an empty list when the ECR repository passed to `list_images` does not exist.


### Expected
The ECR client returns a `RepositoryNotFoundException` exception when the specified repository does not exist in the registry.

See AWS [docs](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ListImages.html).


--- 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/ecr/models.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import hashlib
4 from copy import copy
5 from random import random
6 
7 from moto.core import BaseBackend, BaseModel
8 from moto.ec2 import ec2_backends
9 from moto.ecr.exceptions import ImageNotFoundException, RepositoryNotFoundException
10 
11 from botocore.exceptions import ParamValidationError
12 
13 DEFAULT_REGISTRY_ID = '012345678910'
14 
15 
16 class BaseObject(BaseModel):
17 
18     def camelCase(self, key):
19         words = []
20         for i, word in enumerate(key.split('_')):
21             if i > 0:
22                 words.append(word.title())
23             else:
24                 words.append(word)
25         return ''.join(words)
26 
27     def gen_response_object(self):
28         response_object = copy(self.__dict__)
29         for key, value in response_object.items():
30             if '_' in key:
31                 response_object[self.camelCase(key)] = value
32                 del response_object[key]
33         return response_object
34 
35     @property
36     def response_object(self):
37         return self.gen_response_object()
38 
39 
40 class Repository(BaseObject):
41 
42     def __init__(self, repository_name):
43         self.registry_id = DEFAULT_REGISTRY_ID
44         self.arn = 'arn:aws:ecr:us-east-1:{0}:repository/{1}'.format(
45             self.registry_id, repository_name)
46         self.name = repository_name
47         # self.created = datetime.utcnow()
48         self.uri = '{0}.dkr.ecr.us-east-1.amazonaws.com/{1}'.format(
49             self.registry_id, repository_name)
50         self.images = []
51 
52     @property
53     def physical_resource_id(self):
54         return self.name
55 
56     @property
57     def response_object(self):
58         response_object = self.gen_response_object()
59 
60         response_object['registryId'] = self.registry_id
61         response_object['repositoryArn'] = self.arn
62         response_object['repositoryName'] = self.name
63         response_object['repositoryUri'] = self.uri
64         # response_object['createdAt'] = self.created
65         del response_object['arn'], response_object['name'], response_object['images']
66         return response_object
67 
68     @classmethod
69     def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
70         properties = cloudformation_json['Properties']
71 
72         ecr_backend = ecr_backends[region_name]
73         return ecr_backend.create_repository(
74             # RepositoryName is optional in CloudFormation, thus create a random
75             # name if necessary
76             repository_name=properties.get(
77                 'RepositoryName', 'ecrrepository{0}'.format(int(random() * 10 ** 6))),
78         )
79 
80     @classmethod
81     def update_from_cloudformation_json(cls, original_resource, new_resource_name, cloudformation_json, region_name):
82         properties = cloudformation_json['Properties']
83 
84         if original_resource.name != properties['RepositoryName']:
85             ecr_backend = ecr_backends[region_name]
86             ecr_backend.delete_cluster(original_resource.arn)
87             return ecr_backend.create_repository(
88                 # RepositoryName is optional in CloudFormation, thus create a
89                 # random name if necessary
90                 repository_name=properties.get(
91                     'RepositoryName', 'RepositoryName{0}'.format(int(random() * 10 ** 6))),
92             )
93         else:
94             # no-op when nothing changed between old and new resources
95             return original_resource
96 
97 
98 class Image(BaseObject):
99 
100     def __init__(self, tag, manifest, repository, registry_id=DEFAULT_REGISTRY_ID):
101         self.image_tag = tag
102         self.image_manifest = manifest
103         self.image_size_in_bytes = 50 * 1024 * 1024
104         self.repository = repository
105         self.registry_id = registry_id
106         self.image_digest = None
107         self.image_pushed_at = None
108 
109     def _create_digest(self):
110         image_contents = 'docker_image{0}'.format(int(random() * 10 ** 6))
111         self.image_digest = "sha256:%s" % hashlib.sha256(image_contents.encode('utf-8')).hexdigest()
112 
113     def get_image_digest(self):
114         if not self.image_digest:
115             self._create_digest()
116         return self.image_digest
117 
118     @property
119     def response_object(self):
120         response_object = self.gen_response_object()
121         response_object['imageId'] = {}
122         response_object['imageId']['imageTag'] = self.image_tag
123         response_object['imageId']['imageDigest'] = self.get_image_digest()
124         response_object['imageManifest'] = self.image_manifest
125         response_object['repositoryName'] = self.repository
126         response_object['registryId'] = self.registry_id
127         return response_object
128 
129     @property
130     def response_list_object(self):
131         response_object = self.gen_response_object()
132         response_object['imageTag'] = self.image_tag
133         response_object['imageDigest'] = "i don't know"
134         return response_object
135 
136     @property
137     def response_describe_object(self):
138         response_object = self.gen_response_object()
139         response_object['imageTags'] = [self.image_tag]
140         response_object['imageDigest'] = self.get_image_digest()
141         response_object['imageManifest'] = self.image_manifest
142         response_object['repositoryName'] = self.repository
143         response_object['registryId'] = self.registry_id
144         response_object['imageSizeInBytes'] = self.image_size_in_bytes
145         response_object['imagePushedAt'] = '2017-05-09'
146         return response_object
147 
148     @property
149     def response_batch_get_image(self):
150         response_object = {}
151         response_object['imageId'] = {}
152         response_object['imageId']['imageTag'] = self.image_tag
153         response_object['imageId']['imageDigest'] = self.get_image_digest()
154         response_object['imageManifest'] = self.image_manifest
155         response_object['repositoryName'] = self.repository
156         response_object['registryId'] = self.registry_id
157         return response_object
158 
159 
160 class ECRBackend(BaseBackend):
161 
162     def __init__(self):
163         self.repositories = {}
164 
165     def describe_repositories(self, registry_id=None, repository_names=None):
166         """
167         maxResults and nextToken not implemented
168         """
169         if repository_names:
170             for repository_name in repository_names:
171                 if repository_name not in self.repositories:
172                     raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)
173 
174         repositories = []
175         for repository in self.repositories.values():
176             # If a registry_id was supplied, ensure this repository matches
177             if registry_id:
178                 if repository.registry_id != registry_id:
179                     continue
180             # If a list of repository names was supplied, esure this repository
181             # is in that list
182             if repository_names:
183                 if repository.name not in repository_names:
184                     continue
185             repositories.append(repository.response_object)
186         return repositories
187 
188     def create_repository(self, repository_name):
189         repository = Repository(repository_name)
190         self.repositories[repository_name] = repository
191         return repository
192 
193     def delete_repository(self, repository_name, registry_id=None):
194         if repository_name in self.repositories:
195             return self.repositories.pop(repository_name)
196         else:
197             raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)
198 
199     def list_images(self, repository_name, registry_id=None):
200         """
201         maxResults and filtering not implemented
202         """
203         images = []
204         for repository in self.repositories.values():
205             if repository_name:
206                 if repository.name != repository_name:
207                     continue
208             if registry_id:
209                 if repository.registry_id != registry_id:
210                     continue
211 
212             for image in repository.images:
213                 images.append(image)
214         return images
215 
216     def describe_images(self, repository_name, registry_id=None, image_ids=None):
217 
218         if repository_name in self.repositories:
219             repository = self.repositories[repository_name]
220         else:
221             raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)
222 
223         if image_ids:
224             response = set()
225             for image_id in image_ids:
226                 found = False
227                 for image in repository.images:
228                     if (('imageDigest' in image_id and image.get_image_digest() == image_id['imageDigest']) or
229                             ('imageTag' in image_id and image.image_tag == image_id['imageTag'])):
230                         found = True
231                         response.add(image)
232                 if not found:
233                     image_id_representation = "{imageDigest:'%s', imageTag:'%s'}" % (
234                         image_id.get('imageDigest', 'null'),
235                         image_id.get('imageTag', 'null'),
236                     )
237                     raise ImageNotFoundException(
238                         image_id=image_id_representation,
239                         repository_name=repository_name,
240                         registry_id=registry_id or DEFAULT_REGISTRY_ID)
241 
242         else:
243             response = []
244             for image in repository.images:
245                 response.append(image)
246 
247         return response
248 
249     def put_image(self, repository_name, image_manifest, image_tag):
250         if repository_name in self.repositories:
251             repository = self.repositories[repository_name]
252         else:
253             raise Exception("{0} is not a repository".format(repository_name))
254 
255         image = Image(image_tag, image_manifest, repository_name)
256         repository.images.append(image)
257         return image
258 
259     def batch_get_image(self, repository_name, registry_id=None, image_ids=None, accepted_media_types=None):
260         if repository_name in self.repositories:
261             repository = self.repositories[repository_name]
262         else:
263             raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)
264 
265         if not image_ids:
266             raise ParamValidationError(msg='Missing required parameter in input: "imageIds"')
267 
268         response = {
269             'images': [],
270             'failures': [],
271         }
272 
273         for image_id in image_ids:
274             found = False
275             for image in repository.images:
276                 if (('imageDigest' in image_id and image.get_image_digest() == image_id['imageDigest']) or
277                         ('imageTag' in image_id and image.image_tag == image_id['imageTag'])):
278                     found = True
279                     response['images'].append(image.response_batch_get_image)
280 
281         if not found:
282             response['failures'].append({
283                 'imageId': {
284                     'imageTag': image_id.get('imageTag', 'null')
285                 },
286                 'failureCode': 'ImageNotFound',
287                 'failureReason': 'Requested image not found'
288             })
289 
290         return response
291 
292 
293 ecr_backends = {}
294 for region, ec2_backend in ec2_backends.items():
295     ecr_backends[region] = ECRBackend()
296
```
--- 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/ecr/models.py b/moto/ecr/models.py
--- a/moto/ecr/models.py
+++ b/moto/ecr/models.py
@@ -200,17 +200,22 @@
         """
         maxResults and filtering not implemented
         """
-        images = []
-        for repository in self.repositories.values():
-            if repository_name:
-                if repository.name != repository_name:
-                    continue
+        repository = None
+        found = False
+        if repository_name in self.repositories:
+            repository = self.repositories[repository_name]
             if registry_id:
-                if repository.registry_id != registry_id:
-                    continue
+                if repository.registry_id == registry_id:
+                    found = True
+            else:
+                found = True
 
-            for image in repository.images:
-                images.append(image)
+        if not found:
+            raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)
+
+        images = []
+        for image in repository.images:
+            images.append(image)
         return images
 
     def describe_images(self, repository_name, registry_id=None, image_ids=None):

{"golden_diff": "diff --git a/moto/ecr/models.py b/moto/ecr/models.py\n--- a/moto/ecr/models.py\n+++ b/moto/ecr/models.py\n@@ -200,17 +200,22 @@\n         \"\"\"\n         maxResults and filtering not implemented\n         \"\"\"\n-        images = []\n-        for repository in self.repositories.values():\n-            if repository_name:\n-                if repository.name != repository_name:\n-                    continue\n+        repository = None\n+        found = False\n+        if repository_name in self.repositories:\n+            repository = self.repositories[repository_name]\n             if registry_id:\n-                if repository.registry_id != registry_id:\n-                    continue\n+                if repository.registry_id == registry_id:\n+                    found = True\n+            else:\n+                found = True\n \n-            for image in repository.images:\n-                images.append(image)\n+        if not found:\n+            raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)\n+\n+        images = []\n+        for image in repository.images:\n+            images.append(image)\n         return images\n \n     def describe_images(self, repository_name, registry_id=None, image_ids=None):\n", "issue": "ECR `list_images` should return exception when repository does not exist\n\r\n### Actual\r\n`moto` [will return](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ListImages.html) an empty list when the ECR repository passed to `list_images` does not exist.\r\n\r\n\r\n### Expected\r\nThe ECR client returns a `RepositoryNotFoundException` exception when the specified repository does not exist in the registry.\r\n\r\nSee AWS [docs](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ListImages.html).\r\n\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nimport hashlib\nfrom copy import copy\nfrom random import random\n\nfrom moto.core import BaseBackend, BaseModel\nfrom moto.ec2 import ec2_backends\nfrom moto.ecr.exceptions import ImageNotFoundException, RepositoryNotFoundException\n\nfrom botocore.exceptions import ParamValidationError\n\nDEFAULT_REGISTRY_ID = '012345678910'\n\n\nclass BaseObject(BaseModel):\n\n    def camelCase(self, key):\n        words = []\n        for i, word in enumerate(key.split('_')):\n            if i > 0:\n                words.append(word.title())\n            else:\n                words.append(word)\n        return ''.join(words)\n\n    def gen_response_object(self):\n        response_object = copy(self.__dict__)\n        for key, value in response_object.items():\n            if '_' in key:\n                response_object[self.camelCase(key)] = value\n                del response_object[key]\n        return response_object\n\n    @property\n    def response_object(self):\n        return self.gen_response_object()\n\n\nclass Repository(BaseObject):\n\n    def __init__(self, repository_name):\n        self.registry_id = DEFAULT_REGISTRY_ID\n        self.arn = 'arn:aws:ecr:us-east-1:{0}:repository/{1}'.format(\n            self.registry_id, repository_name)\n        self.name = repository_name\n        # self.created = datetime.utcnow()\n        self.uri = '{0}.dkr.ecr.us-east-1.amazonaws.com/{1}'.format(\n            self.registry_id, repository_name)\n        self.images = []\n\n    @property\n    def physical_resource_id(self):\n        return self.name\n\n    @property\n    def response_object(self):\n        response_object = self.gen_response_object()\n\n        response_object['registryId'] = self.registry_id\n        response_object['repositoryArn'] = self.arn\n        response_object['repositoryName'] = self.name\n        response_object['repositoryUri'] = self.uri\n        # response_object['createdAt'] = self.created\n        del response_object['arn'], response_object['name'], response_object['images']\n        return response_object\n\n    @classmethod\n    def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):\n        properties = cloudformation_json['Properties']\n\n        ecr_backend = ecr_backends[region_name]\n        return ecr_backend.create_repository(\n            # RepositoryName is optional in CloudFormation, thus create a random\n            # name if necessary\n            repository_name=properties.get(\n                'RepositoryName', 'ecrrepository{0}'.format(int(random() * 10 ** 6))),\n        )\n\n    @classmethod\n    def update_from_cloudformation_json(cls, original_resource, new_resource_name, cloudformation_json, region_name):\n        properties = cloudformation_json['Properties']\n\n        if original_resource.name != properties['RepositoryName']:\n            ecr_backend = ecr_backends[region_name]\n            ecr_backend.delete_cluster(original_resource.arn)\n            return ecr_backend.create_repository(\n                # RepositoryName is optional in CloudFormation, thus create a\n                # random name if necessary\n                repository_name=properties.get(\n                    'RepositoryName', 'RepositoryName{0}'.format(int(random() * 10 ** 6))),\n            )\n        else:\n            # no-op when nothing changed between old and new resources\n            return original_resource\n\n\nclass Image(BaseObject):\n\n    def __init__(self, tag, manifest, repository, registry_id=DEFAULT_REGISTRY_ID):\n        self.image_tag = tag\n        self.image_manifest = manifest\n        self.image_size_in_bytes = 50 * 1024 * 1024\n        self.repository = repository\n        self.registry_id = registry_id\n        self.image_digest = None\n        self.image_pushed_at = None\n\n    def _create_digest(self):\n        image_contents = 'docker_image{0}'.format(int(random() * 10 ** 6))\n        self.image_digest = \"sha256:%s\" % hashlib.sha256(image_contents.encode('utf-8')).hexdigest()\n\n    def get_image_digest(self):\n        if not self.image_digest:\n            self._create_digest()\n        return self.image_digest\n\n    @property\n    def response_object(self):\n        response_object = self.gen_response_object()\n        response_object['imageId'] = {}\n        response_object['imageId']['imageTag'] = self.image_tag\n        response_object['imageId']['imageDigest'] = self.get_image_digest()\n        response_object['imageManifest'] = self.image_manifest\n        response_object['repositoryName'] = self.repository\n        response_object['registryId'] = self.registry_id\n        return response_object\n\n    @property\n    def response_list_object(self):\n        response_object = self.gen_response_object()\n        response_object['imageTag'] = self.image_tag\n        response_object['imageDigest'] = \"i don't know\"\n        return response_object\n\n    @property\n    def response_describe_object(self):\n        response_object = self.gen_response_object()\n        response_object['imageTags'] = [self.image_tag]\n        response_object['imageDigest'] = self.get_image_digest()\n        response_object['imageManifest'] = self.image_manifest\n        response_object['repositoryName'] = self.repository\n        response_object['registryId'] = self.registry_id\n        response_object['imageSizeInBytes'] = self.image_size_in_bytes\n        response_object['imagePushedAt'] = '2017-05-09'\n        return response_object\n\n    @property\n    def response_batch_get_image(self):\n        response_object = {}\n        response_object['imageId'] = {}\n        response_object['imageId']['imageTag'] = self.image_tag\n        response_object['imageId']['imageDigest'] = self.get_image_digest()\n        response_object['imageManifest'] = self.image_manifest\n        response_object['repositoryName'] = self.repository\n        response_object['registryId'] = self.registry_id\n        return response_object\n\n\nclass ECRBackend(BaseBackend):\n\n    def __init__(self):\n        self.repositories = {}\n\n    def describe_repositories(self, registry_id=None, repository_names=None):\n        \"\"\"\n        maxResults and nextToken not implemented\n        \"\"\"\n        if repository_names:\n            for repository_name in repository_names:\n                if repository_name not in self.repositories:\n                    raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)\n\n        repositories = []\n        for repository in self.repositories.values():\n            # If a registry_id was supplied, ensure this repository matches\n            if registry_id:\n                if repository.registry_id != registry_id:\n                    continue\n            # If a list of repository names was supplied, esure this repository\n            # is in that list\n            if repository_names:\n                if repository.name not in repository_names:\n                    continue\n            repositories.append(repository.response_object)\n        return repositories\n\n    def create_repository(self, repository_name):\n        repository = Repository(repository_name)\n        self.repositories[repository_name] = repository\n        return repository\n\n    def delete_repository(self, repository_name, registry_id=None):\n        if repository_name in self.repositories:\n            return self.repositories.pop(repository_name)\n        else:\n            raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)\n\n    def list_images(self, repository_name, registry_id=None):\n        \"\"\"\n        maxResults and filtering not implemented\n        \"\"\"\n        images = []\n        for repository in self.repositories.values():\n            if repository_name:\n                if repository.name != repository_name:\n                    continue\n            if registry_id:\n                if repository.registry_id != registry_id:\n                    continue\n\n            for image in repository.images:\n                images.append(image)\n        return images\n\n    def describe_images(self, repository_name, registry_id=None, image_ids=None):\n\n        if repository_name in self.repositories:\n            repository = self.repositories[repository_name]\n        else:\n            raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)\n\n        if image_ids:\n            response = set()\n            for image_id in image_ids:\n                found = False\n                for image in repository.images:\n                    if (('imageDigest' in image_id and image.get_image_digest() == image_id['imageDigest']) or\n                            ('imageTag' in image_id and image.image_tag == image_id['imageTag'])):\n                        found = True\n                        response.add(image)\n                if not found:\n                    image_id_representation = \"{imageDigest:'%s', imageTag:'%s'}\" % (\n                        image_id.get('imageDigest', 'null'),\n                        image_id.get('imageTag', 'null'),\n                    )\n                    raise ImageNotFoundException(\n                        image_id=image_id_representation,\n                        repository_name=repository_name,\n                        registry_id=registry_id or DEFAULT_REGISTRY_ID)\n\n        else:\n            response = []\n            for image in repository.images:\n                response.append(image)\n\n        return response\n\n    def put_image(self, repository_name, image_manifest, image_tag):\n        if repository_name in self.repositories:\n            repository = self.repositories[repository_name]\n        else:\n            raise Exception(\"{0} is not a repository\".format(repository_name))\n\n        image = Image(image_tag, image_manifest, repository_name)\n        repository.images.append(image)\n        return image\n\n    def batch_get_image(self, repository_name, registry_id=None, image_ids=None, accepted_media_types=None):\n        if repository_name in self.repositories:\n            repository = self.repositories[repository_name]\n        else:\n            raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)\n\n        if not image_ids:\n            raise ParamValidationError(msg='Missing required parameter in input: \"imageIds\"')\n\n        response = {\n            'images': [],\n            'failures': [],\n        }\n\n        for image_id in image_ids:\n            found = False\n            for image in repository.images:\n                if (('imageDigest' in image_id and image.get_image_digest() == image_id['imageDigest']) or\n                        ('imageTag' in image_id and image.image_tag == image_id['imageTag'])):\n                    found = True\n                    response['images'].append(image.response_batch_get_image)\n\n        if not found:\n            response['failures'].append({\n                'imageId': {\n                    'imageTag': image_id.get('imageTag', 'null')\n                },\n                'failureCode': 'ImageNotFound',\n                'failureReason': 'Requested image not found'\n            })\n\n        return response\n\n\necr_backends = {}\nfor region, ec2_backend in ec2_backends.items():\n    ecr_backends[region] = ECRBackend()\n", "path": "moto/ecr/models.py"}], "after_files": [{"content": "from __future__ import unicode_literals\n\nimport hashlib\nfrom copy import copy\nfrom random import random\n\nfrom moto.core import BaseBackend, BaseModel\nfrom moto.ec2 import ec2_backends\nfrom moto.ecr.exceptions import ImageNotFoundException, RepositoryNotFoundException\n\nfrom botocore.exceptions import ParamValidationError\n\nDEFAULT_REGISTRY_ID = '012345678910'\n\n\nclass BaseObject(BaseModel):\n\n    def camelCase(self, key):\n        words = []\n        for i, word in enumerate(key.split('_')):\n            if i > 0:\n                words.append(word.title())\n            else:\n                words.append(word)\n        return ''.join(words)\n\n    def gen_response_object(self):\n        response_object = copy(self.__dict__)\n        for key, value in response_object.items():\n            if '_' in key:\n                response_object[self.camelCase(key)] = value\n                del response_object[key]\n        return response_object\n\n    @property\n    def response_object(self):\n        return self.gen_response_object()\n\n\nclass Repository(BaseObject):\n\n    def __init__(self, repository_name):\n        self.registry_id = DEFAULT_REGISTRY_ID\n        self.arn = 'arn:aws:ecr:us-east-1:{0}:repository/{1}'.format(\n            self.registry_id, repository_name)\n        self.name = repository_name\n        # self.created = datetime.utcnow()\n        self.uri = '{0}.dkr.ecr.us-east-1.amazonaws.com/{1}'.format(\n            self.registry_id, repository_name)\n        self.images = []\n\n    @property\n    def physical_resource_id(self):\n        return self.name\n\n    @property\n    def response_object(self):\n        response_object = self.gen_response_object()\n\n        response_object['registryId'] = self.registry_id\n        response_object['repositoryArn'] = self.arn\n        response_object['repositoryName'] = self.name\n        response_object['repositoryUri'] = self.uri\n        # response_object['createdAt'] = self.created\n        del response_object['arn'], response_object['name'], response_object['images']\n        return response_object\n\n    @classmethod\n    def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):\n        properties = cloudformation_json['Properties']\n\n        ecr_backend = ecr_backends[region_name]\n        return ecr_backend.create_repository(\n            # RepositoryName is optional in CloudFormation, thus create a random\n            # name if necessary\n            repository_name=properties.get(\n                'RepositoryName', 'ecrrepository{0}'.format(int(random() * 10 ** 6))),\n        )\n\n    @classmethod\n    def update_from_cloudformation_json(cls, original_resource, new_resource_name, cloudformation_json, region_name):\n        properties = cloudformation_json['Properties']\n\n        if original_resource.name != properties['RepositoryName']:\n            ecr_backend = ecr_backends[region_name]\n            ecr_backend.delete_cluster(original_resource.arn)\n            return ecr_backend.create_repository(\n                # RepositoryName is optional in CloudFormation, thus create a\n                # random name if necessary\n                repository_name=properties.get(\n                    'RepositoryName', 'RepositoryName{0}'.format(int(random() * 10 ** 6))),\n            )\n        else:\n            # no-op when nothing changed between old and new resources\n            return original_resource\n\n\nclass Image(BaseObject):\n\n    def __init__(self, tag, manifest, repository, registry_id=DEFAULT_REGISTRY_ID):\n        self.image_tag = tag\n        self.image_manifest = manifest\n        self.image_size_in_bytes = 50 * 1024 * 1024\n        self.repository = repository\n        self.registry_id = registry_id\n        self.image_digest = None\n        self.image_pushed_at = None\n\n    def _create_digest(self):\n        image_contents = 'docker_image{0}'.format(int(random() * 10 ** 6))\n        self.image_digest = \"sha256:%s\" % hashlib.sha256(image_contents.encode('utf-8')).hexdigest()\n\n    def get_image_digest(self):\n        if not self.image_digest:\n            self._create_digest()\n        return self.image_digest\n\n    @property\n    def response_object(self):\n        response_object = self.gen_response_object()\n        response_object['imageId'] = {}\n        response_object['imageId']['imageTag'] = self.image_tag\n        response_object['imageId']['imageDigest'] = self.get_image_digest()\n        response_object['imageManifest'] = self.image_manifest\n        response_object['repositoryName'] = self.repository\n        response_object['registryId'] = self.registry_id\n        return response_object\n\n    @property\n    def response_list_object(self):\n        response_object = self.gen_response_object()\n        response_object['imageTag'] = self.image_tag\n        response_object['imageDigest'] = \"i don't know\"\n        return response_object\n\n    @property\n    def response_describe_object(self):\n        response_object = self.gen_response_object()\n        response_object['imageTags'] = [self.image_tag]\n        response_object['imageDigest'] = self.get_image_digest()\n        response_object['imageManifest'] = self.image_manifest\n        response_object['repositoryName'] = self.repository\n        response_object['registryId'] = self.registry_id\n        response_object['imageSizeInBytes'] = self.image_size_in_bytes\n        response_object['imagePushedAt'] = '2017-05-09'\n        return response_object\n\n    @property\n    def response_batch_get_image(self):\n        response_object = {}\n        response_object['imageId'] = {}\n        response_object['imageId']['imageTag'] = self.image_tag\n        response_object['imageId']['imageDigest'] = self.get_image_digest()\n        response_object['imageManifest'] = self.image_manifest\n        response_object['repositoryName'] = self.repository\n        response_object['registryId'] = self.registry_id\n        return response_object\n\n\nclass ECRBackend(BaseBackend):\n\n    def __init__(self):\n        self.repositories = {}\n\n    def describe_repositories(self, registry_id=None, repository_names=None):\n        \"\"\"\n        maxResults and nextToken not implemented\n        \"\"\"\n        if repository_names:\n            for repository_name in repository_names:\n                if repository_name not in self.repositories:\n                    raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)\n\n        repositories = []\n        for repository in self.repositories.values():\n            # If a registry_id was supplied, ensure this repository matches\n            if registry_id:\n                if repository.registry_id != registry_id:\n                    continue\n            # If a list of repository names was supplied, esure this repository\n            # is in that list\n            if repository_names:\n                if repository.name not in repository_names:\n                    continue\n            repositories.append(repository.response_object)\n        return repositories\n\n    def create_repository(self, repository_name):\n        repository = Repository(repository_name)\n        self.repositories[repository_name] = repository\n        return repository\n\n    def delete_repository(self, repository_name, registry_id=None):\n        if repository_name in self.repositories:\n            return self.repositories.pop(repository_name)\n        else:\n            raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)\n\n    def list_images(self, repository_name, registry_id=None):\n        \"\"\"\n        maxResults and filtering not implemented\n        \"\"\"\n        repository = None\n        found = False\n        if repository_name in self.repositories:\n            repository = self.repositories[repository_name]\n            if registry_id:\n                if repository.registry_id == registry_id:\n                    found = True\n            else:\n                found = True\n\n        if not found:\n            raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)\n\n        images = []\n        for image in repository.images:\n            images.append(image)\n        return images\n\n    def describe_images(self, repository_name, registry_id=None, image_ids=None):\n\n        if repository_name in self.repositories:\n            repository = self.repositories[repository_name]\n        else:\n            raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)\n\n        if image_ids:\n            response = set()\n            for image_id in image_ids:\n                found = False\n                for image in repository.images:\n                    if (('imageDigest' in image_id and image.get_image_digest() == image_id['imageDigest']) or\n                            ('imageTag' in image_id and image.image_tag == image_id['imageTag'])):\n                        found = True\n                        response.add(image)\n                if not found:\n                    image_id_representation = \"{imageDigest:'%s', imageTag:'%s'}\" % (\n                        image_id.get('imageDigest', 'null'),\n                        image_id.get('imageTag', 'null'),\n                    )\n                    raise ImageNotFoundException(\n                        image_id=image_id_representation,\n                        repository_name=repository_name,\n                        registry_id=registry_id or DEFAULT_REGISTRY_ID)\n\n        else:\n            response = []\n            for image in repository.images:\n                response.append(image)\n\n        return response\n\n    def put_image(self, repository_name, image_manifest, image_tag):\n        if repository_name in self.repositories:\n            repository = self.repositories[repository_name]\n        else:\n            raise Exception(\"{0} is not a repository\".format(repository_name))\n\n        image = Image(image_tag, image_manifest, repository_name)\n        repository.images.append(image)\n        return image\n\n    def batch_get_image(self, repository_name, registry_id=None, image_ids=None, accepted_media_types=None):\n        if repository_name in self.repositories:\n            repository = self.repositories[repository_name]\n        else:\n            raise RepositoryNotFoundException(repository_name, registry_id or DEFAULT_REGISTRY_ID)\n\n        if not image_ids:\n            raise ParamValidationError(msg='Missing required parameter in input: \"imageIds\"')\n\n        response = {\n            'images': [],\n            'failures': [],\n        }\n\n        for image_id in image_ids:\n            found = False\n            for image in repository.images:\n                if (('imageDigest' in image_id and image.get_image_digest() == image_id['imageDigest']) or\n                        ('imageTag' in image_id and image.image_tag == image_id['imageTag'])):\n                    found = True\n                    response['images'].append(image.response_batch_get_image)\n\n        if not found:\n            response['failures'].append({\n                'imageId': {\n                    'imageTag': image_id.get('imageTag', 'null')\n                },\n                'failureCode': 'ImageNotFound',\n                'failureReason': 'Requested image not found'\n            })\n\n        return response\n\n\necr_backends = {}\nfor region, ec2_backend in ec2_backends.items():\n    ecr_backends[region] = ECRBackend()\n", "path": "moto/ecr/models.py"}]}