{ "info": { "author": "George Hickman", "author_email": "george@ghickman.co.uk", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Topic :: Documentation" ], "description": "Classify\n========\n\nGenerate concrete class API documentation for python Classes.\n\nInstallation\n------------\n\n.. code-block:: bash\n\n $ pip install classify\n\n\nUsage\n-----\n\n.. code-block:: bash\n\n $ classify \n\nThis outputs by default to your shell's pager. However you can also generate an\nHTML document to get CCBV_ style pages and even serve that document.\n\nBy default HTML documents are saved to ``/path/to/current/dir/output``.\nTo change this specify a relative location with the ``--output`` option.\n\n.. code-block:: bash\n\n $ classify --html [--output [--serve [--port]]]\n\n\nWhy?\n----\nCCBV_ has long been part of my everyday toolkit for\nworking with Django's class-based views, it's a fantastic resource for quick\nreference. But it only covers Django's CBVs.\n\nClassify aims to be CCBV for all your Python classes.\n\n.. _CCBV: http://ccbv.co.uk\n\n\nAn Example\n----------\n\n.. code-block:: bash\n\n $ classify django.views.generic.CreateView\n\n class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView):\n \"\"\"\n View for creating a new object instance,\n with a response rendered by template.\n \"\"\"\n content_type = None\n context_object_name = None\n form_class = None\n http_method_names = [u'get', u'post', u'put', u'delete', u'head', u'options', u'trace']\n initial = {}\n model = None\n pk_url_kwarg = pk\n queryset = None\n response_class = \n slug_field = slug\n slug_url_kwarg = slug\n success_url = None\n template_name = None\n template_name_field = None\n template_name_suffix = _form\n\n def __init__(self, **kwargs):\n \"\"\"\n Constructor. Called in the URLconf; can contain helpful extra\n keyword arguments, and other things.\n \"\"\"\n # Go through keyword arguments, and either save their values to our\n # instance, or raise an error.\n for key, value in six.iteritems(kwargs):\n setattr(self, key, value)\n\n @classonlymethod\n def as_view(cls, **initkwargs):\n \"\"\"\n Main entry point for a request-response process.\n \"\"\"\n # sanitize keyword arguments\n for key in initkwargs:\n if key in cls.http_method_names:\n raise TypeError(\"You tried to pass in the %s method name as a \"\n \"keyword argument to %s(). Don't do that.\"\n % (key, cls.__name__))\n if not hasattr(cls, key):\n raise TypeError(\"%s() received an invalid keyword %r. as_view \"\n \"only accepts arguments that are already \"\n \"attributes of the class.\" % (cls.__name__, key))\n\n def view(request, *args, **kwargs):\n self = cls(**initkwargs)\n if hasattr(self, 'get') and not hasattr(self, 'head'):\n self.head = self.get\n self.request = request\n self.args = args\n self.kwargs = kwargs\n return self.dispatch(request, *args, **kwargs)\n\n # take name and docstring from class\n update_wrapper(view, cls, updated=())\n\n # and possible attributes set by decorators\n # like csrf_exempt from dispatch\n update_wrapper(view, cls.dispatch, assigned=())\n return view\n\n def dispatch(self, request, *args, **kwargs):\n # Try to dispatch to the right method; if a method doesn't exist,\n # defer to the error handler. Also defer to the error handler if the\n # request method isn't on the approved list.\n if request.method.lower() in self.http_method_names:\n handler = getattr(self, request.method.lower(), self.http_method_not_allowed)\n else:\n handler = self.http_method_not_allowed\n return handler(request, *args, **kwargs)\n\n def form_invalid(self, form):\n \"\"\"\n If the form is invalid, re-render the context data with the\n data-filled form and errors.\n \"\"\"\n return self.render_to_response(self.get_context_data(form=form))\n\n def form_valid(self, form):\n \"\"\"\n If the form is valid, redirect to the supplied URL.\n \"\"\"\n return HttpResponseRedirect(self.get_success_url())\n\n def form_valid(self, form):\n \"\"\"\n If the form is valid, save the associated model.\n \"\"\"\n self.object = form.save()\n return super(ModelFormMixin, self).form_valid(form)\n\n def get(self, request, *args, **kwargs):\n \"\"\"\n Handles GET requests and instantiates a blank version of the form.\n \"\"\"\n form_class = self.get_form_class()\n form = self.get_form(form_class)\n return self.render_to_response(self.get_context_data(form=form))\n\n def get(self, request, *args, **kwargs):\n self.object = None\n return super(BaseCreateView, self).get(request, *args, **kwargs)\n\n def get_context_data(self, **kwargs):\n if 'view' not in kwargs:\n kwargs['view'] = self\n return kwargs\n\n def get_context_data(self, **kwargs):\n \"\"\"\n Insert the single object into the context dict.\n \"\"\"\n context = {}\n context_object_name = self.get_context_object_name(self.object)\n if context_object_name:\n context[context_object_name] = self.object\n context.update(kwargs)\n return super(SingleObjectMixin, self).get_context_data(**context)\n\n def get_context_data(self, **kwargs):\n \"\"\"\n If an object has been supplied, inject it into the context with the\n supplied context_object_name name.\n \"\"\"\n context = {}\n if self.object:\n context['object'] = self.object\n context_object_name = self.get_context_object_name(self.object)\n if context_object_name:\n context[context_object_name] = self.object\n context.update(kwargs)\n return super(ModelFormMixin, self).get_context_data(**context)\n\n def get_context_object_name(self, obj):\n \"\"\"\n Get the name to use for the object.\n \"\"\"\n if self.context_object_name:\n return self.context_object_name\n elif isinstance(obj, models.Model):\n return obj._meta.object_name.lower()\n else:\n return None\n\n def get_form(self, form_class):\n \"\"\"\n Returns an instance of the form to be used in this view.\n \"\"\"\n return form_class(**self.get_form_kwargs())\n\n def get_form_class(self):\n \"\"\"\n Returns the form class to use in this view\n \"\"\"\n return self.form_class\n\n def get_form_class(self):\n \"\"\"\n Returns the form class to use in this view.\n \"\"\"\n if self.form_class:\n return self.form_class\n else:\n if self.model is not None:\n # If a model has been explicitly provided, use it\n model = self.model\n elif hasattr(self, 'object') and self.object is not None:\n # If this view is operating on a single object, use\n # the class of that object\n model = self.object.__class__\n else:\n # Try to get a queryset and extract the model class\n # from that\n model = self.get_queryset().model\n return model_forms.modelform_factory(model)\n\n def get_form_kwargs(self):\n \"\"\"\n Returns the keyword arguments for instantiating the form.\n \"\"\"\n kwargs = {'initial': self.get_initial()}\n if self.request.method in ('POST', 'PUT'):\n kwargs.update({\n 'data': self.request.POST,\n 'files': self.request.FILES,\n })\n return kwargs\n\n def get_form_kwargs(self):\n \"\"\"\n Returns the keyword arguments for instantiating the form.\n \"\"\"\n kwargs = super(ModelFormMixin, self).get_form_kwargs()\n kwargs.update({'instance': self.object})\n return kwargs\n\n def get_initial(self):\n \"\"\"\n Returns the initial data to use for forms on this view.\n \"\"\"\n return self.initial.copy()\n\n def get_object(self, queryset=None):\n \"\"\"\n Returns the object the view is displaying.\n\n By default this requires `self.queryset` and a `pk` or `slug` argument\n in the URLconf, but subclasses can override this to return any object.\n \"\"\"\n # Use a custom queryset if provided; this is required for subclasses\n # like DateDetailView\n if queryset is None:\n queryset = self.get_queryset()\n\n # Next, try looking up by primary key.\n pk = self.kwargs.get(self.pk_url_kwarg, None)\n slug = self.kwargs.get(self.slug_url_kwarg, None)\n if pk is not None:\n queryset = queryset.filter(pk=pk)\n\n # Next, try looking up by slug.\n elif slug is not None:\n slug_field = self.get_slug_field()\n queryset = queryset.filter(**{slug_field: slug})\n\n # If none of those are defined, it's an error.\n else:\n raise AttributeError(\"Generic detail view %s must be called with \"\n \"either an object pk or a slug.\"\n % self.__class__.__name__)\n\n try:\n # Get the single item from the filtered queryset\n obj = queryset.get()\n except ObjectDoesNotExist:\n raise Http404(_(\"No %(verbose_name)s found matching the query\") %\n {'verbose_name': queryset.model._meta.verbose_name})\n return obj\n\n def get_queryset(self):\n \"\"\"\n Get the queryset to look an object up against. May not be called if\n `get_object` is overridden.\n \"\"\"\n if self.queryset is None:\n if self.model:\n return self.model._default_manager.all()\n else:\n raise ImproperlyConfigured(\"%(cls)s is missing a queryset. Define \"\n \"%(cls)s.model, %(cls)s.queryset, or override \"\n \"%(cls)s.get_queryset().\" % {\n 'cls': self.__class__.__name__\n })\n return self.queryset._clone()\n\n def get_slug_field(self):\n \"\"\"\n Get the name of a slug field to be used to look up by slug.\n \"\"\"\n return self.slug_field\n\n def get_success_url(self):\n \"\"\"\n Returns the supplied success URL.\n \"\"\"\n if self.success_url:\n # Forcing possible reverse_lazy evaluation\n url = force_text(self.success_url)\n else:\n raise ImproperlyConfigured(\n \"No URL to redirect to. Provide a success_url.\")\n return url\n\n def get_success_url(self):\n \"\"\"\n Returns the supplied URL.\n \"\"\"\n if self.success_url:\n url = self.success_url % self.object.__dict__\n else:\n try:\n url = self.object.get_absolute_url()\n except AttributeError:\n raise ImproperlyConfigured(\n \"No URL to redirect to. Either provide a url or define\"\n \" a get_absolute_url method on the Model.\")\n return url\n\n def get_template_names(self):\n \"\"\"\n Returns a list of template names to be used for the request. Must return\n a list. May not be called if render_to_response is overridden.\n \"\"\"\n if self.template_name is None:\n raise ImproperlyConfigured(\n \"TemplateResponseMixin requires either a definition of \"\n \"'template_name' or an implementation of 'get_template_names()'\")\n else:\n return [self.template_name]\n\n def get_template_names(self):\n \"\"\"\n Return a list of template names to be used for the request. May not be\n called if render_to_response is overridden. Returns the following list:\n\n * the value of ``template_name`` on the view (if provided)\n * the contents of the ``template_name_field`` field on the\n object instance that the view is operating upon (if available)\n * ``/.html``\n \"\"\"\n try:\n names = super(SingleObjectTemplateResponseMixin, self).get_template_names()\n except ImproperlyConfigured:\n # If template_name isn't specified, it's not a problem --\n # we just start with an empty list.\n names = []\n\n # If self.template_name_field is set, grab the value of the field\n # of that name from the object; this is the most specific template\n # name, if given.\n if self.object and self.template_name_field:\n name = getattr(self.object, self.template_name_field, None)\n if name:\n names.insert(0, name)\n\n # The least-specific option is the default /_detail.html;\n # only use this if the object in question is a model.\n if isinstance(self.object, models.Model):\n names.append(\"%s/%s%s.html\" % (\n self.object._meta.app_label,\n self.object._meta.object_name.lower(),\n self.template_name_suffix\n ))\n elif hasattr(self, 'model') and self.model is not None and issubclass(self.model, models.Model):\n names.append(\"%s/%s%s.html\" % (\n self.model._meta.app_label,\n self.model._meta.object_name.lower(),\n self.template_name_suffix\n ))\n return names\n\n def http_method_not_allowed(self, request, *args, **kwargs):\n logger.warning('Method Not Allowed (%s): %s', request.method, request.path,\n extra={\n 'status_code': 405,\n 'request': self.request\n }\n )\n return http.HttpResponseNotAllowed(self._allowed_methods())\n\n def options(self, request, *args, **kwargs):\n \"\"\"\n Handles responding to requests for the OPTIONS HTTP verb.\n \"\"\"\n response = http.HttpResponse()\n response['Allow'] = ', '.join(self._allowed_methods())\n response['Content-Length'] = '0'\n return response\n\n def post(self, request, *args, **kwargs):\n \"\"\"\n Handles POST requests, instantiating a form instance with the passed\n POST variables and then checked for validity.\n \"\"\"\n form_class = self.get_form_class()\n form = self.get_form(form_class)\n if form.is_valid():\n return self.form_valid(form)\n else:\n return self.form_invalid(form)\n\n def post(self, request, *args, **kwargs):\n self.object = None\n return super(BaseCreateView, self).post(request, *args, **kwargs)\n\n def put(self, *args, **kwargs):\n return self.post(*args, **kwargs)\n\n def render_to_response(self, context, **response_kwargs):\n \"\"\"\n Returns a response, using the `response_class` for this\n view, with a template rendered with the given context.\n\n If any keyword arguments are provided, they will be\n passed to the constructor of the response class.\n \"\"\"\n response_kwargs.setdefault('content_type', self.content_type)\n return self.response_class(\n request = self.request,\n template = self.get_template_names(),\n context = context,\n **response_kwargs\n )", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/ghickman/classify", "keywords": null, "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "classify", "package_url": "https://pypi.org/project/classify/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/classify/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://github.com/ghickman/classify" }, "release_url": "https://pypi.org/project/classify/0.5.0/", "requires_dist": null, "requires_python": null, "summary": "Generate concrete Class documentation for Python Classes.", "version": "0.5.0" }, "last_serial": 921815, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "4cc4a8719f973013c2cbe225ee329695", "sha256": "d84c362ab5b064858fb90e95c43924a59533479853b9509923307d4276e2f0ea" }, "downloads": -1, "filename": "classify-0.1.tar.gz", "has_sig": false, "md5_digest": "4cc4a8719f973013c2cbe225ee329695", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4284, "upload_time": "2013-06-18T22:27:00", "url": "https://files.pythonhosted.org/packages/74/62/93c7ade6431ea4793e90bca6fa693c42e97e4a7d9ad48db4fd3c4f72226c/classify-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "08197ffbb90f2b092c9ee37a6eb769bf", "sha256": "4d6899b36523f71c956cb52b48d25d3724c00ddd5d0045668aa62e07eac723ab" }, "downloads": -1, "filename": "classify-0.2.tar.gz", "has_sig": false, "md5_digest": "08197ffbb90f2b092c9ee37a6eb769bf", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4308, "upload_time": "2013-06-18T22:57:56", "url": "https://files.pythonhosted.org/packages/fd/4b/b142b6313b9ba6178eb1800ca50009b306e9c1caa265e4cd0fd537203a38/classify-0.2.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "ed5aa735464ffcccf0318bdfe26aa68b", "sha256": "e0f2bec5d36aa28ceb14c7edbdda119e23835b7b2f6f04b4164f4b1832c5460f" }, "downloads": -1, "filename": "classify-0.3.tar.gz", "has_sig": false, "md5_digest": "ed5aa735464ffcccf0318bdfe26aa68b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5450, "upload_time": "2013-06-23T11:08:37", "url": "https://files.pythonhosted.org/packages/41/b8/80d3c51d03730b85ca186efda18068b6df85da595945738ba1030d5ba998/classify-0.3.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "3aa86d34b99c8e8ad3d8d6e40acae03b", "sha256": "e622b63b2e6f05d86d76b3d0e2aee51658ada4cd448997171ebbeff54aec6330" }, "downloads": -1, "filename": "classify-0.4.tar.gz", "has_sig": false, "md5_digest": "3aa86d34b99c8e8ad3d8d6e40acae03b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5483, "upload_time": "2013-06-23T11:21:50", "url": "https://files.pythonhosted.org/packages/2f/af/4a03190a20f017e196ff8618a1975d385e295da1c4ed9cd86e1496edc276/classify-0.4.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "134bc4e08727eb8be9aaa0f3a502c061", "sha256": "3a4471d051cf331dcd7a0fd570dcff0af1d62e2dd2efd95514db5ae076bd2356" }, "downloads": -1, "filename": "classify-0.4.1.tar.gz", "has_sig": false, "md5_digest": "134bc4e08727eb8be9aaa0f3a502c061", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11057, "upload_time": "2013-06-27T20:05:24", "url": "https://files.pythonhosted.org/packages/e3/4e/fc531878b8a110e94a1cc508e09c16f08c02d5b437b786018e823f56ef97/classify-0.4.1.tar.gz" } ], "0.5.0": [ { "comment_text": "", "digests": { "md5": "a9b8c9335efe16986b7791e80e3b13f5", "sha256": "fad3a3289f7b649b6de376c5c3fb661c82f678515fc4456ed8720307bfce165b" }, "downloads": -1, "filename": "classify-0.5.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a9b8c9335efe16986b7791e80e3b13f5", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 16725, "upload_time": "2013-11-17T12:06:00", "url": "https://files.pythonhosted.org/packages/9e/ba/2396bab2d31a515755ab72f703a1e1bddc68ae9f96445beae98a6d321ddc/classify-0.5.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a098861fa8992a199707bbf254799ee8", "sha256": "073bd323f465d3ef62e2532f35ff553af7951e377404a3a65bcbec6e7bfea910" }, "downloads": -1, "filename": "classify-0.5.0.tar.gz", "has_sig": false, "md5_digest": "a098861fa8992a199707bbf254799ee8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11180, "upload_time": "2013-06-28T17:39:20", "url": "https://files.pythonhosted.org/packages/31/9c/d76e1c7db52304f0b5a1e82422806ba09ce3d90b68bb4118693d56373e5a/classify-0.5.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a9b8c9335efe16986b7791e80e3b13f5", "sha256": "fad3a3289f7b649b6de376c5c3fb661c82f678515fc4456ed8720307bfce165b" }, "downloads": -1, "filename": "classify-0.5.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a9b8c9335efe16986b7791e80e3b13f5", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 16725, "upload_time": "2013-11-17T12:06:00", "url": "https://files.pythonhosted.org/packages/9e/ba/2396bab2d31a515755ab72f703a1e1bddc68ae9f96445beae98a6d321ddc/classify-0.5.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a098861fa8992a199707bbf254799ee8", "sha256": "073bd323f465d3ef62e2532f35ff553af7951e377404a3a65bcbec6e7bfea910" }, "downloads": -1, "filename": "classify-0.5.0.tar.gz", "has_sig": false, "md5_digest": "a098861fa8992a199707bbf254799ee8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11180, "upload_time": "2013-06-28T17:39:20", "url": "https://files.pythonhosted.org/packages/31/9c/d76e1c7db52304f0b5a1e82422806ba09ce3d90b68bb4118693d56373e5a/classify-0.5.0.tar.gz" } ] }