{"action":"created","issue":{"url":"https://api.github.com/repos/nyaruka/rapidpro/issues/108","labels_url":"https://api.github.com/repos/nyaruka/rapidpro/issues/108/labels{/name}","comments_url":"https://api.github.com/repos/nyaruka/rapidpro/issues/108/comments","events_url":"https://api.github.com/repos/nyaruka/rapidpro/issues/108/events","html_url":"https://github.com/nyaruka/rapidpro/pull/108","id":60641078,"number":108,"title":"Assets","user":{"login":"rowanseymour","id":675558,"avatar_url":"https://avatars.githubusercontent.com/u/675558?v=3","gravatar_id":"","url":"https://api.github.com/users/rowanseymour","html_url":"https://github.com/rowanseymour","followers_url":"https://api.github.com/users/rowanseymour/followers","following_url":"https://api.github.com/users/rowanseymour/following{/other_user}","gists_url":"https://api.github.com/users/rowanseymour/gists{/gist_id}","starred_url":"https://api.github.com/users/rowanseymour/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rowanseymour/subscriptions","organizations_url":"https://api.github.com/users/rowanseymour/orgs","repos_url":"https://api.github.com/users/rowanseymour/repos","events_url":"https://api.github.com/users/rowanseymour/events{/privacy}","received_events_url":"https://api.github.com/users/rowanseymour/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":9,"created_at":"2015-03-11T10:56:05Z","updated_at":"2015-03-19T15:31:24Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/nyaruka/rapidpro/pulls/108","html_url":"https://github.com/nyaruka/rapidpro/pull/108","diff_url":"https://github.com/nyaruka/rapidpro/pull/108.diff","patch_url":"https://github.com/nyaruka/rapidpro/pull/108.patch"},"body":"An app for restricted access to files in storage. Provides 3 different types of URL for assets:\r\n * Landing pages: http://localhost:8000/assets/download/contact_export/1234/\r\n * Direct downloads: http://localhost:8000/assets/stream/contact_export/1234/\r\n * API access: http://localhost:8000/api/v1/assets?type=contact_export&identifier=1234\r\n\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/nyaruka/rapidpro/issues/comments/83634040","html_url":"https://github.com/nyaruka/rapidpro/pull/108#issuecomment-83634040","issue_url":"https://api.github.com/repos/nyaruka/rapidpro/issues/108","id":83634040,"user":{"login":"rowanseymour","id":675558,"avatar_url":"https://avatars.githubusercontent.com/u/675558?v=3","gravatar_id":"","url":"https://api.github.com/users/rowanseymour","html_url":"https://github.com/rowanseymour","followers_url":"https://api.github.com/users/rowanseymour/followers","following_url":"https://api.github.com/users/rowanseymour/following{/other_user}","gists_url":"https://api.github.com/users/rowanseymour/gists{/gist_id}","starred_url":"https://api.github.com/users/rowanseymour/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rowanseymour/subscriptions","organizations_url":"https://api.github.com/users/rowanseymour/orgs","repos_url":"https://api.github.com/users/rowanseymour/repos","events_url":"https://api.github.com/users/rowanseymour/events{/privacy}","received_events_url":"https://api.github.com/users/rowanseymour/received_events","type":"User","site_admin":false},"created_at":"2015-03-19T15:31:24Z","updated_at":"2015-03-19T15:31:24Z","body":"Perhaps worth listing out how different types of exceptions are used - I can think of at least 3 different ways that we use them:\r\n\r\n1. As sanity checks for us - often these are `ValueError` instances with no localization, and `# pragma: no cover`. They don't ever become user facing but they might end up in our logs.\r\n2. As something to be translated into a user facing error message - for example `ValidationError` instances in forms and API. Users see them, so they need localized messages.\r\n3. For internal flow - we raise and catch these internally, thus there's not much use for them to have error messages. For example the asset related ones in this PR and `EvaluationError` in the expression parser.\r\n\r\nIf we introduced our own exception base class then we could use it for case #1 (though not much to be gained since `ValueError` does the job just fine). For case #3 we could use it as a base for exceptions like those in the assets app. Again though.. am not seeing much benefit.\r\n\r\nRegarding naming, PEP8 says exceptions should _Error_ name suffix (https://www.python.org/dev/peps/pep-0008/#exception-names) and it is 4 less characters to type..."}}