Contributing
Woo! You're more than welcome to contribute! Everything takes place on our GitHub repo.
Here's what you need to know.
Building
This is a Django project running on Python 3. As such, you'll need to get a python environment up and running. We suggest the following:
# Fork the project # Get the project git clone git@github.com:[YOUR USER]/explore621 cd explore621 # Set up a virtualenv virtualenv venv --python=`which python3` source venv/bin/activate # Install dependencies pip install -r requirements.txt # Set up your dev database cd e621 ./manage.py migrate # Import some data (this will take a while...) # You can specify how many pages to retrieve, and how many posts per page. # You must specify your username - this doesn't log you in or anything, just # adds your username to the user-agent string. This lets e621 know who to # contact if there's a problem. ./manage.py refresh --pages 5 --per-page 100 [YOUR e621 USERNAME] # Run the server ./manage.py runserver
You should then be able to navigate to 127.0.0.1:8000 and see everything up and running.
Working on the site.
There's likely one thing you'll want to do more than any other with the project, and that's work with reports. Each report relies on a runner, which is the bit of code that actually munges the data from the database and stores it in a result. Runners come in two parts: the bit that grabs the data, and the bit that displays that.
Grabbing the data
You can add or modify runners in reports/runners/
. Each of these extends reports.runners.base.BaseRunner
, and should implement the run
and generate_result
methods. run
generally performs all of the database heavy lifting and usually stores the result in self.result
, while generate_result
calls self.set_result
to set the string that will be passed to the front end. In practice, the content of generate_result
is usually just self.set_result(json.dumps(self.result))
.
If you add a new runner, you will need to add it to the RUNNERS
dict in reports/runners/__init__.py
so that it can be used by reports.models.Report.run
.
Runners can accept attributes from reports. Each report has an attributes
attribute which contains a JSON string. In BaseRunner
, this string is loaded, and then the key/value pairs added to the runner as class attributes. That is, if your report has the attributes='{"tags":["fox","wolf"]}'
, then your runner will wind up with self.tags = ['fox', 'wolf']
. If you want to require a tag, you can use ensure_attribute
within the runner's __init__()
, and if you want a tag to be optional but have a default value, you can use default_attribute
:
class MyRunner(BaseRunner): def __init__(self, report): super().__init__(report) self.ensure_attribute('tags') self.default_attribute('count', 1) # ...
This is also the place to check the content of tags.
Finally, runners should have a help_text
attribute which contains a markdown string describing it and listing expected attributes. See the existing runners for the expected style.
Displaying the data
For each runner, there exists a means of displaying it using JavaScript and SVG. This is done through a function in static/js/runners.js
named exactly the same as the runner in the RUNNERS
dict above. This should simply get the container element using d3 and pass off the heavy lifting to a function in static/js/vis.js
. There are a few existing visualization utilities available in there, so consider using (or modifying) one of those before writing a new one!
Building a report
If you've got a report you would like to see that would be served by one of the runners, you can easily do that in Python land. Get into the Django shell by running ./manage.py shell
and then use that as your playground.
from reports.models import Report report = Report( title='foo', description='bar', frequency='on_demand', runner='MyRunner', attributes='{"baz":"qux"}') report.save() run = report.run() run.result # ...
When you have something that you like and want to see implemented on explore621, create a pull request with your runner changes if needed, then file an issue with the report you would like to see (using the constructor as above, if possible!).