Sphinx documentation and autodoc-skip-member - django

I'm building my sphinx doc for a django project the following way:
sphinx-apidoc app -o docs/source/app --force
Now it includes all of the South migrations which I don't want to have in my documentation. I now tried to exclude them the following way:
conf.py:
def skip_migrations(app, what, name, obj, skip, options):
return skip or (what == 'module' and name.find('Migration') != -1)\
or str(obj).find('migrations') != -1
def setup(app):
app.connect('autodoc-skip-member', skip_migrations)
Now they aren't documented anymore, but are still listed under modules. How can I exclude them?

You may exclude the rst files created for the migrations by adding them to the exclude_pattern in your conf.py file:
exclude_patterns = ["**/*.migrations.rst",]

Just avoid generating the .rst files with sphinx-apidoc in the first place:
sphinx-apidoc app -o docs/source/app --force */migrations/*
Patterns added after the module name are understood as excluded paths.

Related

Sphinx builtin themes not found

In my conf.py it says I should see the documentation for a list of builtin-themes. Now my first google hit leads me to http://www.sphinx-doc.org/en/stable/theming.html#builtin-themes . There are a bunch of themes in there which my sphinx does not know about. For example 'classic'.
in conf.py
html_theme = 'classic'
On my shell I do: sphinx-build -b html source build
writing output... [100%] index
Exception occurred:
File "~\appdata\local\programs\python\python35\lib\site-packages\sphinx\jinja2glue.py", line 200, in get_source
raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: about.html
sphinx version: 1.6.3.
I had same problem because I used alabaster theme before. There are a few lines in conf.py that are needed for alabaster and break other themes. You need to comment them out.
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
# html_sidebars = {
# '**': [
# 'about.html',
# 'navigation.html',
# 'relations.html', # needs 'show_related': True theme option to display
# 'searchbox.html',
# 'donate.html',
# ]
# }
It is an issue after changing alabaster theme to another one that doesn't use about.html. Laurent said the workaround.
Issue:
https://github.com/sphinx-doc/sphinx/issues/3987

How to customize TRAC plugin template python file

I am currently modifying our TRAC instance to Bootstrap 3.1. However, some templating needs to be done on the .py files. I only know how to customize .html files... just add classes, customize DOM structure a little bit then put it in templates folder of our TRAC instance.
NOW WHAT ABOUT customizing .py files from plugins? I tried putting them in templates folder but nothing happened.
I had no experience with Python, but it's easy just to hack around and add a bootstrap class e.g adding "col-sm-2 control-label" in a label in milestone.py
def __edit_project(self, data, req):
milestone = data.get('milestone').name
all_projects = self.__SmpModel.get_all_projects_filtered_by_conditions(req)
id_project_milestone = self.__SmpModel.get_id_project_milestone(milestone)
if id_project_milestone != None:
id_project_selected = id_project_milestone[0]
else:
id_project_selected = None
return tag.div(
tag.label(
class_="col-sm-2 control-label",
'Project',
tag.br(),
tag.select(
tag.option(),
[tag.option(row[1], selected=(id_project_selected == row[0] or None), value=row[0]) for row in sorted(all_projects, key=itemgetter(1))],
name="project")
),
class_="field")
Compiling the plugin again worked for me. After adding bootstrap classes on specific .py files, here are the steps/commands I did:
In our TRAC environment plugins directory where specific setup.py of the plugin I'm editing is located, build the .egg file e.g
tracproject/plugins_source/sampleplugin: python setup.py bdist_egg
Then I renamed the plugin's original .egg file in the plugins directory e.g
tracproject/plugins/sampleplugin/: mv sampleplugin.egg sampleplugin.egg.old
After that, I copied the newly .egg file generated to the plugins directory e.g
tracproject/plugins_source/sampleplugin/dist: mv sampleplugin.egg ../../../plugins/
Lastly, I restarted our server e.g (however, there were cases, no restart was needed since changes were instantly reflected)
sudo service apache2 restart
Thanks #falkb! I see that you're the author of SimpleMultiProject plugin I was trying to put bootstrap classes. :)
Here's a snippet of simplemultiprojectplugin milestone.py where I added styling
def __edit_project(self, data, req):
milestone = data.get('milestone').name
all_projects = self.__SmpModel.get_all_projects_filtered_by_conditions(req)
id_project_milestone = self.__SmpModel.get_id_project_milestone(milestone)
if id_project_milestone != None:
id_project_selected = id_project_milestone[0]
else:
id_project_selected = None
return tag.div(
tag.label('Project', class_="control-label col-sm-2"),
tag.div(
tag.select(
tag.option(),
[tag.option(row[1], selected=(id_project_selected == row[0] or None), value=row[0]) for row in sorted(all_projects, key=itemgetter(1))],
name="project",
class_="form-control"),
class_="col-sm-5"),
class_="form-group")

Django Static Files: Any Way to Get More Fine-Grained Control?

Django's static files feature allows you to specify certain directories to have "collected" in to a public-facing folder. That's great, but is there any way to get more fine-grained control than just having certain folders? For instance, is there anyway to specify ...
Including specific files
Excluding specific files
Excluding specific sub-directories
For instance, I'd like to say "collect all the files in this one folder except for this one file and this one directory". Alternatively, I could accomplish the same thing if I could pick specific files, and then pick all of the sub-directories of that one directory (except the one I don't want).
Is any of that possible?
I wrote a custom django-admin command to enable a COLLECT_STATIC_IGNORE setting.
First create the following stucture in any app folder:
appname/
management/
__init__.py
commands/
__init__.py
_private.py
collectstatic.py
In collectstatic.py put:
from django.contrib.staticfiles.management.commands.collectstatic import Command
from django.conf import settings
class Command(Command):
def set_options(self, **options):
"""
Set instance variables based on an options dict
"""
self.interactive = options['interactive']
self.verbosity = int(options.get('verbosity', 1))
self.symlink = options['link']
self.clear = options['clear']
self.dry_run = options['dry_run']
ignore_patterns = options['ignore_patterns']
if options['use_default_ignore_patterns']:
ignore_patterns += ['CVS', '.*', '*~']
ignore_patterns += settings.COLLECT_STATIC_IGNORE # Added.
self.ignore_patterns = list(set(ignore_patterns))
self.post_process = options['post_process']
Or, even better, like #CantucciHQ suggested, use super:
class Command(Command):
def set_options(self, **options):
super(Command, self).set_options(**options)
self.ignore_patterns += settings.COLLECT_STATIC_IGNORE
self.ignore_patterns = list(set(self.ignore_patterns))
This overrides the set_options function from de build-in collectstatic command.
In settings.py add COLLECT_STATIC_IGNORE.
This example ignores scss files and all files in admin folders.
COLLECT_STATIC_IGNORE = ['*.scss', 'admin', ... ]
Then:
python manage.py collectstatic
Flags work so after adding something to COLLECT_STATIC_IGNORE you might want to use --clear to clear the existing files before trying to copy or link the original file.
python manage.py collectstatic --clear

How do I ignore static files of a particular app only with collectstatic?

Just to get this out of the way, if at all possible, I'd like to do this without nesting them all inside a directory with the app's name inside the app's static folder, it feels redundant. If it's the only way then such is life.
I am using:
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
and:
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
which compiles the JS and SASS when running collectstatic. These are both located in the APP_ROOT/static/ directory.
The only 'problem' is that it brings along all the source sass and js files alongside it. At some point I'm going to be pushing this all to S3 and I'd like to avoid that if possible.
I found that if you run:
python manage.py collectstatic -i sass -i js
It still compiles the JS and CSS files I specified, while leaving the rest of the 'source' files out. Unfortunately, it also ignores every js file in /admin/ as it matches /admin/js/ etc. I don't even know if that's likely to be a problem for this particular project, but I can foresee in the future other apps where I definitely will want to include static js/css kept in an app.
What I'd like to be able to do is something like:
python manage.py collectstatic -i app_name/sass -i app_name/js
And as I mentioned at the top the easy solution is just to prefix my static files in the folder with app_name/, much like how django.contrib.admin does it. At this point however, you end up with a directory structure of PROJECT_ROOT/app_name/static/app_name/[js|sass|img|data]/ and I think it should be possible to avoid the redundancy.
Then again, maybe it's the best option, so as to guarantee avoiding conflict with other apps?
I've looked into writing custom storages and finders, and I think it's possible to roll my own. I wanted to check here though first, to see if this is a problem someone else has solved, or, to get a reality check if the overwhelming response is to just add the prefix directory.
If I was to roll my own, the path I think I would take would be extending django.contrib.staticfiles.finders.AppDirectoriesFinder and overriding list(). I'm not yet positive this approach would work, I need to more trace how things progress from the collectstatic management command, so if anyone has done this or something simlilar before, or knows why it will/won't work, any help is appreciated.
Thanks!
I managed to solve this by subclassing Django finders like this:
PYTHON 2.X
from django.contrib.staticfiles import finders
from django.conf import settings
def add_ignores(ignore_patterns):
ignore = settings.STATICFILES_FINDERS_IGNORE
if ignore:
if ignore_patterns:
ignore_patterns.extend(ignore)
else:
ignore_patterns = ignore
return ignore_patterns
class FileSystemFinderIgnore(finders.FileSystemFinder):
def list(self, ignore_patterns):
return super(FileSystemFinderIgnore, self).list(add_ignores(ignore_patterns))
class AppDirectoriesFinderIgnore(finders.AppDirectoriesFinder):
def list(self, ignore_patterns):
return super(AppDirectoriesFinderIgnore, self).list(add_ignores(ignore_patterns))
class DefaultStorageFinderIgnore(finders.DefaultStorageFinder):
def list(self, ignore_patterns):
return super(DefaultStorageFinderIgnore, self).list(add_ignores(ignore_patterns))
PYTHON 3.X
from django.contrib.staticfiles import finders
from django.conf import settings
def add_ignores(ignore_patterns):
ignore = settings.STATICFILES_FINDERS_IGNORE
if ignore:
if ignore_patterns:
ignore_patterns.extend(ignore)
else:
ignore_patterns = ignore
return ignore_patterns
class FileSystemFinderIgnore(finders.FileSystemFinder):
def list(self, ignore_patterns):
return super().list(add_ignores(ignore_patterns))
class AppDirectoriesFinderIgnore(finders.AppDirectoriesFinder):
def list(self, ignore_patterns):
return super().list(add_ignores(ignore_patterns))
class DefaultStorageFinderIgnore(finders.DefaultStorageFinder):
def list(self, ignore_patterns):
return super().list(add_ignores(ignore_patterns))
and adding this to my settings:
STATICFILES_FINDERS_IGNORE = [
'*.scss',
'*.js',
]
I'm new to django-pipeline, but I believe it now has pipeline.finders.FileSystemFinder and pipeline.finders.AppDirectoriesFinder to do exactly this.
See the section "If you want to exclude Pipelinable content from your collected static files" on https://django-pipeline.readthedocs.org/en/latest/storages.html.
Also, from the source code of 1.5:
class AppDirectoriesFinder(PatternFilterMixin, DjangoAppDirectoriesFinder):
"""
Like AppDirectoriesFinder, but doesn't return any additional ignored
patterns.
This allows us to concentrate/compress our components without dragging
the raw versions in via collectstatic.
"""
Note that at the time of writing, this results in empty compressed/minified content when DEBUG==True, see https://github.com/cyberdelia/django-pipeline/issues/418. I assume this will be fixed in future versions of django-pipeline.

Django makemessages ignore switch doesn't work for me

I have problems localizing a django-nonrel project, which is deployed to GAE. Because of GAE I have to put everything into my project folder, so it looks like something like this
project
+ django
+ dbindexer
+ registration
+ myapp
...
+ locale
+ templates
I have strings to localize in templates directory, and in the myapp directory.
When I run python manage.py makemessages -l en --ignore django\* from the project dir it crawl through all the directories of the project, including django, so I get a quite big po file. My strings from the templates are there, along with all of the strings from django directory.
after --ignore ( or just -i ) I tried to pu django django/* , but nothing changed.
Any ideas?
./manage.py help makemessages
-i PATTERN, --ignore=PATTERN
Ignore files or directories matching this glob-style
pattern. Use multiple times to ignore more.
I have just tested it, and this command successfully ignored my application:
./manage.py makemessages -l da -i "django*"
But beware that before you test it, you should delete the old .po file, as I think it will not automatically remove the translation lines from your previous makemessages execution.
The problem is with the pattern - maybe the shell was expanding it for you.
In general - it is good to avoid path separators (whether / or \) in the pattern.
If you need to always pass specific options to the makemessages command, you could consider your own wrapper, like this one, which I use myself:
from django.conf import settings
from django.core.management.base import BaseCommand
from django.core.management import call_command
class Command(BaseCommand):
help = "Scan i18n messages without going into externals."
def handle(self, *args, **options):
call_command('makemessages',
all=True,
extensions=['html', 'inc'],
ignore_patterns=['externals*'])
This saves you typing, and gives a common entry point for scanning messages across the project (your translator colleague will not destroy translations by missing out some parameter).
Don't delete the old .po file, once you have cleared it from the totally unwanted (i.e. - those from 'django' directory) messages. This allows gettext to recycle old unused messages, once they are used again (or simmilar ones, which will be marked as #, fuzzy.
Edit - as mt4x noted - the wrapper above doesn't allow for passing the options to the wrapped command. This is easy to fix:
from django.core.management import call_command
from django.core.management.commands.makemessages import (
Command as MakeMessagesCommand
)
class Command(MakeMessagesCommand):
help = "Scan i18n messages without going into externals."
def handle(self, *args, **options):
options['all'] = True
options['extensions'] = ['html', 'inc']
if 'ignore_patterns' not in options:
options['ignore_patterns'] = []
options['ignore_patterns'] += ['externals*']
call_command('makemessages', **options)
Thus - you can fix what needs to be fixed, and flex the rest.
And this needs not be blind override like above, but also some conditional edit of the parameters passed to the command - appending something to a list or only adding it when it's missing.