DEV Community

Cover image for Keep a source log, get a clean reference list: a free Python research kit for APA and MLA
Plagiarism Checker X
Plagiarism Checker X

Posted on AI-assisted

Keep a source log, get a clean reference list: a free Python research kit for APA and MLA

Most citation mistakes in essays and theses don't happen while writing the reference list. They happen weeks earlier, when you read a paper, copy a quote into your notes and forget the page number. Or you save the same article twice under slightly different titles.

Plagx Research Kit is a free, open-source notebook that fixes this at the source. You log each source as you read it, and Python turns the log into a correct APA 7 or MLA 9 reference list. It also checks the log for duplicates and missing details, and compares your draft's in-text citations against it.

πŸ‘‰ Open the notebook in Google Colab. Click Runtime β†’ Run all. No setup is needed.

It also gives you templates to download: a source log, a literature matrix, an annotated bibliography and a research plan.

1. The source log

A source log is a spreadsheet with one row per source. These columns are the minimum you need to cite a source and find it again later:

Column Example
id smith2020
type article-journal, book, chapter, webpage
authors Smith, John Allen; Lee, Kate
year, title, container Year, title, and journal/book/site name
volume, issue, pages, doi, url Whatever applies
notes, quote, quote_page Your summary, plus any exact quote with its page number

Recording the page number next to every quote is the habit that saves the most time later.

2. From log row to citation

The notebook uses plagx-cite, an MIT-licensed Python package with no dependencies. It works with CSL-JSON, the format Zotero, Mendeley and Crossref export, so each log row is mapped to one CSL-JSON reference:

pip install plagx-cite
Enter fullscreen mode Exit fullscreen mode
from plagx_cite import format_reference, cite_in_text

ref = {
    "id": "smith2020",
    "type": "article-journal",
    "title": "Feedback timing and revision quality in undergraduate essays",
    "author": [{"family": "Smith", "given": "John Allen"}, {"family": "Lee", "given": "Kate"}],
    "issued": {"date-parts": [[2020]]},
    "container-title": "Journal of Academic Writing",
    "volume": "12", "issue": "3", "page": "45-67",
    "DOI": "10.1234/jaw.2020.045",
}

print(format_reference(ref))
# Smith, J. A., & Lee, K. (2020). Feedback timing and revision quality in undergraduate essays.
# Journal of Academic Writing, 12(3), 45–67. https://doi.org/10.1234/jaw.2020.045

print(cite_in_text(ref, page="52"))               # (Smith & Lee, 2020, p. 52)
print(cite_in_text(ref, narrative=True))          # Smith and Lee (2020)
print(cite_in_text(ref, style="mla", page="52"))  # (Smith and Lee 52)
Enter fullscreen mode Exit fullscreen mode

The example sources here and in the notebook are made up. The DOIs aren't real.

3. Check the log before you write

check_references finds duplicates (same DOI, or same title and first author) and missing details. In the notebook's example log, the same paper was saved twice: once with title-case capitalisation and a full https://doi.org/ link, and once without. Another source has no year:

from plagx_cite import check_references

report = check_references(refs)
for issue in report["issues"]:
    print(issue["level"], issue["ref"], issue["message"])

# error   smith2020b  Possible duplicate (doi and title match) of smith2020: smith2020, smith2020b
# warning chen2021    No year (will show as n.d.)
Enter fullscreen mode Exit fullscreen mode

The check runs locally and nothing is sent over the network. DOI lookups are optional and off by default.

4. Match the draft against the log

The most common reference-list mistake is a source cited in the text that never made it into the list, or the other way round. The notebook finds APA-style citations such as (Smith & Lee, 2020, p. 52) or Garcia (2018) with a regular expression and compares them with the log:

import re

CITATION = re.compile(r"([A-Z][\w'-]+)(?: (?:&|and) [A-Z][\w'-]+| et al\.)?,? \(?(\d{4})")

draft = """Early feedback changes how students revise (Smith & Lee, 2020, p. 52).
Garcia (2018) recommends paraphrasing from notes. Several studies support
peer review (Chen, 2021; Patel, 2019)."""

cited = {(name.lower(), year) for name, year in CITATION.findall(draft)}
logged = {("smith", "2020"), ("garcia", "2018"), ("chen", "2021"), ("okafor", "2022")}

print("Cited but not logged:", cited - logged)   # {('patel', '2019')}
print("Logged but not cited:", logged - cited)   # {('okafor', '2022')}
Enter fullscreen mode Exit fullscreen mode

It's a simple pattern match and won't catch every citation format, but it catches the mistakes that cost marks.

5. Templates

The last cells write everything to an output folder and download it as a zip:

  • source_log_template.csv: a blank log with the columns above
  • literature_matrix.csv: compare sources by method, findings, limitations and themes
  • annotated_bibliography.md: formatted references with your notes under each
  • research_plan.md: research question, scope, search strategy table and timeline
  • references.json / references.bib: your sources as CSL-JSON and BibTeX, for Zotero, Mendeley or LaTeX

To use your own sources, upload your log (File β†’ Save a copy in Drive first), and the same cells build your reference list and templates.

Links


By Plagiarism Checker X. This kit formats citations and checks your source log. It doesn't check for plagiarism or detect AI-generated text. For full plagiarism checks and AI-generated text detection, visit the Text Similarity Detector.

Top comments (0)