{"action":"created","comment":{"url":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/comments/27951869","id":27951869,"diff_hunk":"@@ -0,0 +1,83 @@\n+from io import BytesIO\n+\n+import factory\n+from PIL import Image\n+\n+\n+TEST_SERVER = 'http://testserver'\n+\n+\n+def simple_png():\n+    \"\"\"Create a 1x1 black png in memory and return a handle to it.\"\"\"\n+    image_file = BytesIO()\n+    image = Image.new('RGBA', (1, 1))\n+    image.save(image_file, 'png')\n+    image_file.name = 'test.png'\n+    image_file.url = '{0}/{1}'.format(\n+        TEST_SERVER,\n+        image_file.name,\n+    )\n+    image_file._committed = True\n+    image_file.seek(0)\n+    return image_file\n+\n+\n+class LocalFileField(factory.django.FileField):\n+    \"\"\"\n+    A factory file field class that creates an image in memory.\n+\n+    Suitable for using as a FileField or ImageField.\n+\n+        class ATestFactory(factory.Factory):\n+            file = LocalFileField()\n+    \"\"\"\n+    def __init__(self, *args, **kwargs):\n+        defaults = {\n+            'from_path': 'incuna_test_utils/factories/images/image.png',\n+        }\n+        defaults.update(kwargs)\n+        super(LocalFileField, self).__init__(*args, **defaults)\n+\n+\n+class SimplePngFileField(factory.LazyAttribute):\n+    \"\"\"\n+    A factory file field class that creates an image in memory.\n+\n+    Suitable for using as a FileField or ImageField.\n+\n+        class ATestFactory(factory.Factory):\n+            file = SimplePngFileField()\n+    \"\"\"\n+    def __init__(self, method=None, *args, **kwargs):\n+        if not method:\n+            def png(a):\n+                return simple_png()\n+            method = png\n+        super(SimplePngFileField, self).__init__(method, *args, **kwargs)\n+\n+\n+def uploadable_file():\n+    \"\"\"\n+    Return an object that can be uploaded to a FileField via a Django form.\n+\n+    Uploading files in a form in a test can be a pain.  One way that works well is to\n+    use a `factory.django.FileField` to create a fully featured Django file object, then\n+    upload that via `request.FILES`.  This method returns the file object.\n+\n+    Example usage:\n+\n+        file_data = {\n+            'file_field_name': uploadable_file(),\n+        }\n+        form = form_class_being_tested(files=file_data)\n+\n+    Note that the form_class_being_tested is instantiated using the `files` kwarg and not\n+    `data`.  The two are not mutually exclusive, but the file being uploaded must be\n+    passed in using `files`, which correlates to `request.FILES`. Other form data can be\n+    passed in using `data` as normal.\n+    \"\"\"\n+    class FileFactory(factory.StubFactory):\n+        file = LocalFileField()\n+\n+    model = FileFactory.stub()\n+    return model.file.file","path":"incuna_test_utils/factories/images.py","position":83,"original_position":83,"commit_id":"8e18b628ca3fefab4f301fa1ce3e65bb7e569872","original_commit_id":"8e18b628ca3fefab4f301fa1ce3e65bb7e569872","user":{"login":"meshy","id":767671,"avatar_url":"https://avatars.githubusercontent.com/u/767671?v=3","gravatar_id":"","url":"https://api.github.com/users/meshy","html_url":"https://github.com/meshy","followers_url":"https://api.github.com/users/meshy/followers","following_url":"https://api.github.com/users/meshy/following{/other_user}","gists_url":"https://api.github.com/users/meshy/gists{/gist_id}","starred_url":"https://api.github.com/users/meshy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/meshy/subscriptions","organizations_url":"https://api.github.com/users/meshy/orgs","repos_url":"https://api.github.com/users/meshy/repos","events_url":"https://api.github.com/users/meshy/events{/privacy}","received_events_url":"https://api.github.com/users/meshy/received_events","type":"User","site_admin":false},"body":"Fair enough. Perhaps this can be done without the factory, then? What does the StubFactory actually do here?","created_at":"2015-04-08T08:39:30Z","updated_at":"2015-04-08T08:39:30Z","html_url":"https://github.com/incuna/incuna-test-utils/pull/52#discussion_r27951869","pull_request_url":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/52","_links":{"self":{"href":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/comments/27951869"},"html":{"href":"https://github.com/incuna/incuna-test-utils/pull/52#discussion_r27951869"},"pull_request":{"href":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/52"}}},"pull_request":{"url":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/52","id":32782927,"html_url":"https://github.com/incuna/incuna-test-utils/pull/52","diff_url":"https://github.com/incuna/incuna-test-utils/pull/52.diff","patch_url":"https://github.com/incuna/incuna-test-utils/pull/52.patch","issue_url":"https://api.github.com/repos/incuna/incuna-test-utils/issues/52","number":52,"state":"open","locked":false,"title":"Add file factory utilities","user":{"login":"adam-incuna","id":6973481,"avatar_url":"https://avatars.githubusercontent.com/u/6973481?v=3","gravatar_id":"","url":"https://api.github.com/users/adam-incuna","html_url":"https://github.com/adam-incuna","followers_url":"https://api.github.com/users/adam-incuna/followers","following_url":"https://api.github.com/users/adam-incuna/following{/other_user}","gists_url":"https://api.github.com/users/adam-incuna/gists{/gist_id}","starred_url":"https://api.github.com/users/adam-incuna/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/adam-incuna/subscriptions","organizations_url":"https://api.github.com/users/adam-incuna/orgs","repos_url":"https://api.github.com/users/adam-incuna/repos","events_url":"https://api.github.com/users/adam-incuna/events{/privacy}","received_events_url":"https://api.github.com/users/adam-incuna/received_events","type":"User","site_admin":false},"body":"* Add `simple_png()` method that creates a small file in memory.\n* Add two `FileField` subclasses that provide content based on a) a file on disk and b) the aforementioned `simple_png()`.\n* Add an `uploadable_file()` method that will return something that can be uploaded to a form.\n\n@incuna/backend review please?","created_at":"2015-04-07T16:49:06Z","updated_at":"2015-04-08T08:39:30Z","closed_at":null,"merged_at":null,"merge_commit_sha":"029cf4e6b974f3a1b96db4178a4aeb07b9dbb4e3","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/52/commits","review_comments_url":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/52/comments","review_comment_url":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/comments{/number}","comments_url":"https://api.github.com/repos/incuna/incuna-test-utils/issues/52/comments","statuses_url":"https://api.github.com/repos/incuna/incuna-test-utils/statuses/8e18b628ca3fefab4f301fa1ce3e65bb7e569872","head":{"label":"incuna:image-factories","ref":"image-factories","sha":"8e18b628ca3fefab4f301fa1ce3e65bb7e569872","user":{"login":"incuna","id":55510,"avatar_url":"https://avatars.githubusercontent.com/u/55510?v=3","gravatar_id":"","url":"https://api.github.com/users/incuna","html_url":"https://github.com/incuna","followers_url":"https://api.github.com/users/incuna/followers","following_url":"https://api.github.com/users/incuna/following{/other_user}","gists_url":"https://api.github.com/users/incuna/gists{/gist_id}","starred_url":"https://api.github.com/users/incuna/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/incuna/subscriptions","organizations_url":"https://api.github.com/users/incuna/orgs","repos_url":"https://api.github.com/users/incuna/repos","events_url":"https://api.github.com/users/incuna/events{/privacy}","received_events_url":"https://api.github.com/users/incuna/received_events","type":"Organization","site_admin":false},"repo":{"id":15281429,"name":"incuna-test-utils","full_name":"incuna/incuna-test-utils","owner":{"login":"incuna","id":55510,"avatar_url":"https://avatars.githubusercontent.com/u/55510?v=3","gravatar_id":"","url":"https://api.github.com/users/incuna","html_url":"https://github.com/incuna","followers_url":"https://api.github.com/users/incuna/followers","following_url":"https://api.github.com/users/incuna/following{/other_user}","gists_url":"https://api.github.com/users/incuna/gists{/gist_id}","starred_url":"https://api.github.com/users/incuna/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/incuna/subscriptions","organizations_url":"https://api.github.com/users/incuna/orgs","repos_url":"https://api.github.com/users/incuna/repos","events_url":"https://api.github.com/users/incuna/events{/privacy}","received_events_url":"https://api.github.com/users/incuna/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/incuna/incuna-test-utils","description":"TestCases and other helpers for testing Django apps.","fork":false,"url":"https://api.github.com/repos/incuna/incuna-test-utils","forks_url":"https://api.github.com/repos/incuna/incuna-test-utils/forks","keys_url":"https://api.github.com/repos/incuna/incuna-test-utils/keys{/key_id}","collaborators_url":"https://api.github.com/repos/incuna/incuna-test-utils/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/incuna/incuna-test-utils/teams","hooks_url":"https://api.github.com/repos/incuna/incuna-test-utils/hooks","issue_events_url":"https://api.github.com/repos/incuna/incuna-test-utils/issues/events{/number}","events_url":"https://api.github.com/repos/incuna/incuna-test-utils/events","assignees_url":"https://api.github.com/repos/incuna/incuna-test-utils/assignees{/user}","branches_url":"https://api.github.com/repos/incuna/incuna-test-utils/branches{/branch}","tags_url":"https://api.github.com/repos/incuna/incuna-test-utils/tags","blobs_url":"https://api.github.com/repos/incuna/incuna-test-utils/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/incuna/incuna-test-utils/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/incuna/incuna-test-utils/git/refs{/sha}","trees_url":"https://api.github.com/repos/incuna/incuna-test-utils/git/trees{/sha}","statuses_url":"https://api.github.com/repos/incuna/incuna-test-utils/statuses/{sha}","languages_url":"https://api.github.com/repos/incuna/incuna-test-utils/languages","stargazers_url":"https://api.github.com/repos/incuna/incuna-test-utils/stargazers","contributors_url":"https://api.github.com/repos/incuna/incuna-test-utils/contributors","subscribers_url":"https://api.github.com/repos/incuna/incuna-test-utils/subscribers","subscription_url":"https://api.github.com/repos/incuna/incuna-test-utils/subscription","commits_url":"https://api.github.com/repos/incuna/incuna-test-utils/commits{/sha}","git_commits_url":"https://api.github.com/repos/incuna/incuna-test-utils/git/commits{/sha}","comments_url":"https://api.github.com/repos/incuna/incuna-test-utils/comments{/number}","issue_comment_url":"https://api.github.com/repos/incuna/incuna-test-utils/issues/comments{/number}","contents_url":"https://api.github.com/repos/incuna/incuna-test-utils/contents/{+path}","compare_url":"https://api.github.com/repos/incuna/incuna-test-utils/compare/{base}...{head}","merges_url":"https://api.github.com/repos/incuna/incuna-test-utils/merges","archive_url":"https://api.github.com/repos/incuna/incuna-test-utils/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/incuna/incuna-test-utils/downloads","issues_url":"https://api.github.com/repos/incuna/incuna-test-utils/issues{/number}","pulls_url":"https://api.github.com/repos/incuna/incuna-test-utils/pulls{/number}","milestones_url":"https://api.github.com/repos/incuna/incuna-test-utils/milestones{/number}","notifications_url":"https://api.github.com/repos/incuna/incuna-test-utils/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/incuna/incuna-test-utils/labels{/name}","releases_url":"https://api.github.com/repos/incuna/incuna-test-utils/releases{/id}","created_at":"2013-12-18T11:30:35Z","updated_at":"2015-03-27T15:34:11Z","pushed_at":"2015-04-07T16:49:06Z","git_url":"git://github.com/incuna/incuna-test-utils.git","ssh_url":"git@github.com:incuna/incuna-test-utils.git","clone_url":"https://github.com/incuna/incuna-test-utils.git","svn_url":"https://github.com/incuna/incuna-test-utils","homepage":"","size":1055,"stargazers_count":4,"watchers_count":4,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":7,"forks":3,"open_issues":7,"watchers":4,"default_branch":"master"}},"base":{"label":"incuna:master","ref":"master","sha":"ddee13805c0286fdcf5b1714bf25c2b5a5e59a5d","user":{"login":"incuna","id":55510,"avatar_url":"https://avatars.githubusercontent.com/u/55510?v=3","gravatar_id":"","url":"https://api.github.com/users/incuna","html_url":"https://github.com/incuna","followers_url":"https://api.github.com/users/incuna/followers","following_url":"https://api.github.com/users/incuna/following{/other_user}","gists_url":"https://api.github.com/users/incuna/gists{/gist_id}","starred_url":"https://api.github.com/users/incuna/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/incuna/subscriptions","organizations_url":"https://api.github.com/users/incuna/orgs","repos_url":"https://api.github.com/users/incuna/repos","events_url":"https://api.github.com/users/incuna/events{/privacy}","received_events_url":"https://api.github.com/users/incuna/received_events","type":"Organization","site_admin":false},"repo":{"id":15281429,"name":"incuna-test-utils","full_name":"incuna/incuna-test-utils","owner":{"login":"incuna","id":55510,"avatar_url":"https://avatars.githubusercontent.com/u/55510?v=3","gravatar_id":"","url":"https://api.github.com/users/incuna","html_url":"https://github.com/incuna","followers_url":"https://api.github.com/users/incuna/followers","following_url":"https://api.github.com/users/incuna/following{/other_user}","gists_url":"https://api.github.com/users/incuna/gists{/gist_id}","starred_url":"https://api.github.com/users/incuna/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/incuna/subscriptions","organizations_url":"https://api.github.com/users/incuna/orgs","repos_url":"https://api.github.com/users/incuna/repos","events_url":"https://api.github.com/users/incuna/events{/privacy}","received_events_url":"https://api.github.com/users/incuna/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/incuna/incuna-test-utils","description":"TestCases and other helpers for testing Django apps.","fork":false,"url":"https://api.github.com/repos/incuna/incuna-test-utils","forks_url":"https://api.github.com/repos/incuna/incuna-test-utils/forks","keys_url":"https://api.github.com/repos/incuna/incuna-test-utils/keys{/key_id}","collaborators_url":"https://api.github.com/repos/incuna/incuna-test-utils/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/incuna/incuna-test-utils/teams","hooks_url":"https://api.github.com/repos/incuna/incuna-test-utils/hooks","issue_events_url":"https://api.github.com/repos/incuna/incuna-test-utils/issues/events{/number}","events_url":"https://api.github.com/repos/incuna/incuna-test-utils/events","assignees_url":"https://api.github.com/repos/incuna/incuna-test-utils/assignees{/user}","branches_url":"https://api.github.com/repos/incuna/incuna-test-utils/branches{/branch}","tags_url":"https://api.github.com/repos/incuna/incuna-test-utils/tags","blobs_url":"https://api.github.com/repos/incuna/incuna-test-utils/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/incuna/incuna-test-utils/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/incuna/incuna-test-utils/git/refs{/sha}","trees_url":"https://api.github.com/repos/incuna/incuna-test-utils/git/trees{/sha}","statuses_url":"https://api.github.com/repos/incuna/incuna-test-utils/statuses/{sha}","languages_url":"https://api.github.com/repos/incuna/incuna-test-utils/languages","stargazers_url":"https://api.github.com/repos/incuna/incuna-test-utils/stargazers","contributors_url":"https://api.github.com/repos/incuna/incuna-test-utils/contributors","subscribers_url":"https://api.github.com/repos/incuna/incuna-test-utils/subscribers","subscription_url":"https://api.github.com/repos/incuna/incuna-test-utils/subscription","commits_url":"https://api.github.com/repos/incuna/incuna-test-utils/commits{/sha}","git_commits_url":"https://api.github.com/repos/incuna/incuna-test-utils/git/commits{/sha}","comments_url":"https://api.github.com/repos/incuna/incuna-test-utils/comments{/number}","issue_comment_url":"https://api.github.com/repos/incuna/incuna-test-utils/issues/comments{/number}","contents_url":"https://api.github.com/repos/incuna/incuna-test-utils/contents/{+path}","compare_url":"https://api.github.com/repos/incuna/incuna-test-utils/compare/{base}...{head}","merges_url":"https://api.github.com/repos/incuna/incuna-test-utils/merges","archive_url":"https://api.github.com/repos/incuna/incuna-test-utils/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/incuna/incuna-test-utils/downloads","issues_url":"https://api.github.com/repos/incuna/incuna-test-utils/issues{/number}","pulls_url":"https://api.github.com/repos/incuna/incuna-test-utils/pulls{/number}","milestones_url":"https://api.github.com/repos/incuna/incuna-test-utils/milestones{/number}","notifications_url":"https://api.github.com/repos/incuna/incuna-test-utils/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/incuna/incuna-test-utils/labels{/name}","releases_url":"https://api.github.com/repos/incuna/incuna-test-utils/releases{/id}","created_at":"2013-12-18T11:30:35Z","updated_at":"2015-03-27T15:34:11Z","pushed_at":"2015-04-07T16:49:06Z","git_url":"git://github.com/incuna/incuna-test-utils.git","ssh_url":"git@github.com:incuna/incuna-test-utils.git","clone_url":"https://github.com/incuna/incuna-test-utils.git","svn_url":"https://github.com/incuna/incuna-test-utils","homepage":"","size":1055,"stargazers_count":4,"watchers_count":4,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":7,"forks":3,"open_issues":7,"watchers":4,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/52"},"html":{"href":"https://github.com/incuna/incuna-test-utils/pull/52"},"issue":{"href":"https://api.github.com/repos/incuna/incuna-test-utils/issues/52"},"comments":{"href":"https://api.github.com/repos/incuna/incuna-test-utils/issues/52/comments"},"review_comments":{"href":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/52/comments"},"review_comment":{"href":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/incuna/incuna-test-utils/pulls/52/commits"},"statuses":{"href":"https://api.github.com/repos/incuna/incuna-test-utils/statuses/8e18b628ca3fefab4f301fa1ce3e65bb7e569872"}}}}