openansho 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openansho-0.1.0/.gitignore +13 -0
- openansho-0.1.0/CLAUDE.md +83 -0
- openansho-0.1.0/LICENSE +21 -0
- openansho-0.1.0/Makefile +171 -0
- openansho-0.1.0/PKG-INFO +140 -0
- openansho-0.1.0/README.md +99 -0
- openansho-0.1.0/images/kanji_shou_app_icon.png +0 -0
- openansho-0.1.0/images/kanji_shou_app_icon.svg +9 -0
- openansho-0.1.0/pyproject.toml +97 -0
- openansho-0.1.0/src/openansho/__init__.py +1 -0
- openansho-0.1.0/src/openansho/__main__.py +39 -0
- openansho-0.1.0/src/openansho/db.py +363 -0
- openansho-0.1.0/src/openansho/reporting.py +153 -0
- openansho-0.1.0/src/openansho/text_extract.py +97 -0
- openansho-0.1.0/src/openansho/tutorial.py +41 -0
- openansho-0.1.0/src/openansho/tutorial.txt +31 -0
- openansho-0.1.0/src/openansho/ui/__init__.py +0 -0
- openansho-0.1.0/src/openansho/ui/checkable_combo_box.py +121 -0
- openansho-0.1.0/src/openansho/ui/code_filter_input.py +19 -0
- openansho-0.1.0/src/openansho/ui/code_tree.py +30 -0
- openansho-0.1.0/src/openansho/ui/font_scale.py +75 -0
- openansho-0.1.0/src/openansho/ui/main_window.py +2082 -0
- openansho-0.1.0/src/openansho/ui/merge_codes_dialog.py +69 -0
- openansho-0.1.0/src/openansho/ui/os_theme.py +59 -0
- openansho-0.1.0/src/openansho/ui/preferences_dialog.py +57 -0
- openansho-0.1.0/src/openansho/ui/report_dialog.py +45 -0
- openansho-0.1.0/src/openansho/ui/shortcuts_dialog.py +97 -0
- openansho-0.1.0/src/openansho/ui/vim_viewer.py +858 -0
- openansho-0.1.0/src/openansho/user.py +86 -0
- openansho-0.1.0/tests/conftest.py +23 -0
- openansho-0.1.0/tests/test_always_selected_code.py +227 -0
- openansho-0.1.0/tests/test_code_drag_drop.py +175 -0
- openansho-0.1.0/tests/test_code_filter.py +112 -0
- openansho-0.1.0/tests/test_code_filter_selection.py +262 -0
- openansho-0.1.0/tests/test_code_sorting.py +154 -0
- openansho-0.1.0/tests/test_codebook.py +347 -0
- openansho-0.1.0/tests/test_coding.py +369 -0
- openansho-0.1.0/tests/test_db.py +298 -0
- openansho-0.1.0/tests/test_docx_import.py +169 -0
- openansho-0.1.0/tests/test_export_ui.py +151 -0
- openansho-0.1.0/tests/test_font_scale.py +177 -0
- openansho-0.1.0/tests/test_highlight_bands.py +202 -0
- openansho-0.1.0/tests/test_main_window.py +143 -0
- openansho-0.1.0/tests/test_new_code_placeholder.py +232 -0
- openansho-0.1.0/tests/test_os_theme.py +129 -0
- openansho-0.1.0/tests/test_packaging.py +39 -0
- openansho-0.1.0/tests/test_pane_focus_outline.py +110 -0
- openansho-0.1.0/tests/test_reporting.py +198 -0
- openansho-0.1.0/tests/test_shortcuts_popup.py +44 -0
- openansho-0.1.0/tests/test_tutorial.py +75 -0
- openansho-0.1.0/tests/test_user_filter.py +341 -0
- openansho-0.1.0/tests/test_username.py +263 -0
- openansho-0.1.0/tests/test_vim_integration.py +794 -0
- openansho-0.1.0/tests/test_vim_viewer.py +739 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## What this is
|
|
6
|
+
|
|
7
|
+
OpenAnsho is a desktop app (PySide6/Qt) for qualitative data analysis: importing text documents, tagging ("coding") spans of text with a hierarchical codebook, and exporting/reporting on the coded segments. Projects are single `.sqlite` files.
|
|
8
|
+
|
|
9
|
+
## Development setup
|
|
10
|
+
|
|
11
|
+
First-time setup, run once from the repo root:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
python3 -m venv .venv # create the project virtualenv
|
|
15
|
+
source .venv/bin/activate # activate it
|
|
16
|
+
pip install -e ".[dev]" # install package + dev deps (pytest, pytest-qt)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Every subsequent session, activate the virtualenv before running any commands below:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
source .venv/bin/activate # activate the project virtualenv
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
To run the development version of the app (with the virtualenv active):
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python -m openansho # run the app (or the `openansho` console script)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
The project uses a `.venv` virtualenv at the repo root — activate it before running any of the commands below.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
source .venv/bin/activate # activate the project virtualenv
|
|
37
|
+
pip install -e ".[dev]" # install package + dev deps (pytest, pytest-qt)
|
|
38
|
+
python -m openansho # run the app (or the `openansho` console script)
|
|
39
|
+
pytest # run the full test suite
|
|
40
|
+
pytest tests/test_db.py::test_create_code_and_list_codes # run a single test
|
|
41
|
+
make dist # build the PyPI sdist + wheel into dist/pypi
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
There is no configured linter/formatter/type-checker in `pyproject.toml` — don't assume `ruff`/`black`/`mypy` are wired in.
|
|
45
|
+
|
|
46
|
+
**Known hang: the full suite in Claude Code's sandbox.** Running the unscoped suite (bare `pytest`, or `pytest tests/`) reliably hangs in Claude Code's sandboxed/offscreen environment — the process gets stuck in an uninterruptible sleep that not even `kill -9` can clear, apparently a Qt/native-windowing issue with `tests/test_always_selected_code.py` specifically when it runs alongside the rest of the suite (it passes in well under a second in isolation, e.g. `pytest tests/test_always_selected_code.py`). `pytest tests/ --ignore=tests/test_always_selected_code.py` runs the rest of the suite (142 tests) in about a second. Claude Code should scope test runs (a single file, `--ignore` that file, or `-k`) rather than invoking the bare full suite. The human developer should still run the full suite occasionally outside this sandbox (a normal local terminal), since that's the only way to catch a regression in the one file this workaround always excludes.
|
|
47
|
+
|
|
48
|
+
## Distribution
|
|
49
|
+
|
|
50
|
+
The app ships through two channels, and a change to how the app finds its files has to work in both:
|
|
51
|
+
|
|
52
|
+
- **Prebuilt executables** via PyInstaller (`make build-mac`/`build-windows`/`build-linux`, published to the `builds` branch by `.github/workflows/ci.yml`).
|
|
53
|
+
- **A PyPI sdist + wheel** (`make dist`, published by `.github/workflows/release.yml` on a `v*` tag via trusted publishing; `make publish` is the manual fallback). Releasing means bumping `__version__` in `src/openansho/__init__.py` — hatchling reads the version from there, so `pyproject.toml` has none of its own — then pushing a matching tag, which the workflow verifies against `__version__` before uploading.
|
|
54
|
+
|
|
55
|
+
Consequences worth knowing before touching the packaging:
|
|
56
|
+
|
|
57
|
+
- **`__main__._icon_path` has three branches** because the icon lives in a different place in each layout: `sys._MEIPASS/images/` in a PyInstaller bundle, next to the package in an installed wheel (pyproject `force-include`s `images/kanji_shou_app_icon.png` into `openansho/`, since a wheel has no repo root), and `images/` at the repo root when running from source. Package data added in the future needs the same treatment — `tutorial.txt` avoids it by living inside the package to begin with, which is the simpler option.
|
|
58
|
+
- **`user.username_file` picks a directory based on how the app was installed.** Frozen builds and source checkouts own their directory, so the `.openansho_user` sidecar sits next to the app as before; a pip install would otherwise write into site-packages, which can be read-only and is replaced wholesale on upgrade, so `user.installed_in_site_packages()` routes it to `user.config_directory()` instead.
|
|
59
|
+
- **The entry point is a `gui-script`, not a `console script`**, so the Windows launcher is built against `pythonw` and doesn't leave a console window behind the app. `python -m openansho` is the console-attached form to recommend when someone needs a traceback.
|
|
60
|
+
- `tests/test_packaging.py` covers the layout-dependent paths; `tests/conftest.py` pins `installed_in_site_packages` off so the suite never touches a real config directory.
|
|
61
|
+
|
|
62
|
+
## Architecture
|
|
63
|
+
|
|
64
|
+
**Layering:** `db.py` → `reporting.py`/`text_extract.py`/`tutorial.py` → `ui/*`. The non-UI modules have zero Qt imports and operate directly on a `sqlite3.Connection`, so they're usable from tests (or a future CLI) without spinning up a `QApplication`.
|
|
65
|
+
|
|
66
|
+
- **`db.py`** — the only place that touches SQL. Three tables: `documents`, `codes` (self-referencing via `parent_id`, `ON DELETE CASCADE`), `segments` (document + code + `start_offset`/`end_offset` char range + optional memo). Note `delete_code` re-parents a deleted code's children to its own parent *before* deleting, specifically to dodge the cascade that would otherwise wipe out the whole subtree.
|
|
67
|
+
- **`reporting.py`** — read-only aggregation/export over `db.py` (CSV/JSON segment export, code-frequency counts). `code_path()` builds the "Parent > Child" breadcrumb by walking `parent_id` up to the root.
|
|
68
|
+
- **`text_extract.py`** — `read_document_text(path)` turns a file into the plain text that gets stored in `documents.content`, dispatching on extension: `.docx` goes through a hand-rolled `zipfile`+`ElementTree` reader (no `python-docx`, so the packaged app keeps PySide6 as its only dependency), anything else is read as UTF-8. Failures raise `DocumentReadError` whose message is shown verbatim in the import dialog.
|
|
69
|
+
- **`tutorial.py`** — the built-in tutorial project the app opens at startup (`__main__.main` calls `MainWindow.open_tutorial_project`, also reachable via File > Open Tutorial). `open_tutorial_project()` returns a `db.connect(":memory:")` connection seeded with `tutorial.txt`, which ships as package data next to the module — the in-memory database is the whole mechanism for "the tutorial codebook is never saved," so don't give it a file path. `MainWindow._set_connection` accepts `path=None` for exactly this project: no file to title the window after and nothing to put in Open Recent.
|
|
70
|
+
- **`ui/main_window.py`** — the app. `MainWindow` methods split into two groups by convention: `_on_*` slots that own dialog/QMessageBox interaction, and plain methods (`create_project`, `import_document`, `add_code`, `apply_segment`, `delete_code`, ...) that contain the actual logic and take/return plain values. Tests drive the app through the latter, never through the `_on_*` slots or real file dialogs.
|
|
71
|
+
- **`ui/vim_viewer.py`** — `VimTextViewer`, a read-only `QPlainTextEdit` with hand-rolled vim motions (`hjkl`, `w/b/e` vs `W/B/E` WORD variants, `0/$`, `gg/G`, viewport-relative `H/L`, visual mode via `v`). It disables the native blinking cursor (`setCursorWidth(0)`) and instead renders its own block-cursor highlight as an `ExtraSelection`, layered alongside the per-code highlight selections from `MainWindow`.
|
|
72
|
+
- **`ui/code_tree.py`** — `CodeTreeWidget`, adds internal drag-and-drop re-parenting on top of `QTreeWidget`, emitting `codeReparented(code_id, new_parent_id)` for `MainWindow` to persist (and validate — no self-parenting, no moving under one's own descendant).
|
|
73
|
+
- **`ui/code_filter_input.py`** — `CodeFilterLineEdit`, a `QLineEdit` that repurposes Up/Down to cycle the currently-matched code instead of moving the text cursor.
|
|
74
|
+
- **`ui/report_dialog.py`** — plain read-only table dialog for the code-frequency report.
|
|
75
|
+
- **`ui/font_scale.py`** — application-wide font scaling, expressed as a percentage of the platform's default UI font. Scaling has to be applied *twice* to actually take effect: `apply_font_scale` sets `QApplication`'s font (what later-created dialogs/menus start from), and `font_scale_style` returns a `QWidget { font-size: … }` fragment that `MainWindow._apply_theme` appends to the theme stylesheet — setting any stylesheet makes Qt give each polished widget an explicit font, which then stops tracking `QApplication`'s, so already-built panes only resize via the stylesheet. Note Qt's QSS parser silently rejects fractional point sizes, hence the rounding in `scaled_font`.
|
|
76
|
+
|
|
77
|
+
**Cross-pane keyboard model:** `MainWindow` installs a `QApplication`-wide `eventFilter` (not per-widget handlers) so a handful of shortcuts work regardless of which pane has focus: Space jumps focus to the code filter, Up/Down cycle the matched/highlighted code when the viewer has a selection, Enter applies the current code to the viewer's selection, and `x` deletes segments touching the cursor (normal mode) or the current selection (visual mode). When adding a new global shortcut, it goes here, not on an individual widget.
|
|
78
|
+
|
|
79
|
+
**Focus styling:** panes are visually highlighted on focus via a Qt dynamic property (`"focused"`) toggled from `QApplication.focusChanged`, matched by the QSS in `PANE_FOCUS_STYLE` — not via per-widget `focusInEvent` overrides.
|
|
80
|
+
|
|
81
|
+
**Coding workflow invariant:** applying a code always goes through `MainWindow.apply_segment`, which both writes the segment (`db.create_segment`) and refreshes the code tree/highlights/segment list in one place — don't call `db.create_segment` directly from UI code.
|
|
82
|
+
|
|
83
|
+
**Keyboard shortcuts must stay documented.** `ui/shortcuts_dialog.py`'s `SHORTCUT_SECTIONS` is shown to the user via the `?` popup and is the single source of truth for "what keys does this app respond to." Any time a keyboard shortcut is added, changed, or removed anywhere in the UI (the global `eventFilter` in `main_window.py`, vim motions in `vim_viewer.py`, `code_filter_input.py`, `code_tree.py`, or any `QShortcut`/menu accelerator), update `SHORTCUT_SECTIONS` in the same change so the popup never drifts out of sync with actual behavior.
|
openansho-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zachary del Rosario
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
openansho-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Makefile for building the OpenAnsho desktop app with PyInstaller.
|
|
2
|
+
#
|
|
3
|
+
# PyInstaller does not cross-compile: it can only build an executable for
|
|
4
|
+
# the OS it runs on. So build-mac must run on macOS, build-windows on
|
|
5
|
+
# Windows, and build-linux on Linux (e.g. as separate jobs in a CI matrix).
|
|
6
|
+
# `make build` builds for whichever platform you're currently on.
|
|
7
|
+
|
|
8
|
+
APP_NAME := OpenAnsho
|
|
9
|
+
ENTRY_POINT := src/openansho/__main__.py
|
|
10
|
+
ICON := images/kanji_shou_app_icon.png
|
|
11
|
+
TUTORIAL := src/openansho/tutorial.txt
|
|
12
|
+
DIST_DIR := dist
|
|
13
|
+
BUILD_DIR := build
|
|
14
|
+
VENV := .venv
|
|
15
|
+
|
|
16
|
+
# --add-data uses a platform-specific separator between source and destination.
|
|
17
|
+
ifeq ($(OS),Windows_NT)
|
|
18
|
+
VENV_BIN := $(VENV)/Scripts
|
|
19
|
+
SYSTEM_PYTHON := python
|
|
20
|
+
ADD_DATA := $(ICON);images
|
|
21
|
+
ADD_TUTORIAL := $(TUTORIAL);openansho
|
|
22
|
+
else
|
|
23
|
+
VENV_BIN := $(VENV)/bin
|
|
24
|
+
SYSTEM_PYTHON := python3
|
|
25
|
+
ADD_DATA := $(ICON):images
|
|
26
|
+
ADD_TUTORIAL := $(TUTORIAL):openansho
|
|
27
|
+
endif
|
|
28
|
+
|
|
29
|
+
PYTHON := $(VENV_BIN)/python
|
|
30
|
+
PIP := $(VENV_BIN)/pip
|
|
31
|
+
PYINSTALLER := $(VENV_BIN)/pyinstaller
|
|
32
|
+
PYTEST := $(VENV_BIN)/pytest
|
|
33
|
+
|
|
34
|
+
PYPI_DIR := $(DIST_DIR)/pypi
|
|
35
|
+
|
|
36
|
+
.PHONY: help venv install install-build install-publish test clean build build-mac build-windows build-linux dist publish publish-test
|
|
37
|
+
|
|
38
|
+
help:
|
|
39
|
+
@echo "Targets:"
|
|
40
|
+
@echo " venv Create the virtualenv at $(VENV)"
|
|
41
|
+
@echo " install Install the package with dev dependencies"
|
|
42
|
+
@echo " install-build Install PyInstaller into the virtualenv"
|
|
43
|
+
@echo " test Run the full test suite"
|
|
44
|
+
@echo " build-mac Build a macOS .app bundle (must run on macOS)"
|
|
45
|
+
@echo " build-windows Build a Windows .exe (must run on Windows)"
|
|
46
|
+
@echo " build-linux Build a Linux binary (must run on Linux)"
|
|
47
|
+
@echo " build Build for the current platform"
|
|
48
|
+
@echo " dist Build the PyPI sdist + wheel into $(PYPI_DIR)"
|
|
49
|
+
@echo " publish-test Upload the sdist + wheel to TestPyPI"
|
|
50
|
+
@echo " publish Upload the sdist + wheel to PyPI"
|
|
51
|
+
@echo " clean Remove build/dist artifacts and .spec files"
|
|
52
|
+
|
|
53
|
+
$(VENV_BIN)/python:
|
|
54
|
+
$(SYSTEM_PYTHON) -m venv $(VENV)
|
|
55
|
+
|
|
56
|
+
venv: $(VENV_BIN)/python
|
|
57
|
+
|
|
58
|
+
install: venv
|
|
59
|
+
$(PIP) install -e ".[dev]"
|
|
60
|
+
|
|
61
|
+
install-build: venv
|
|
62
|
+
$(PIP) install -e ".[build]"
|
|
63
|
+
|
|
64
|
+
install-publish: venv
|
|
65
|
+
$(PIP) install -e ".[publish]"
|
|
66
|
+
|
|
67
|
+
# Note: the full suite is known to hang in Claude Code's sandboxed/offscreen
|
|
68
|
+
# environment (see CLAUDE.md) — this target is meant for a real terminal or CI.
|
|
69
|
+
test: install
|
|
70
|
+
$(PYTEST)
|
|
71
|
+
|
|
72
|
+
clean:
|
|
73
|
+
rm -rf $(BUILD_DIR) $(DIST_DIR) *.spec
|
|
74
|
+
|
|
75
|
+
# --- Platform builds --------------------------------------------------------
|
|
76
|
+
#
|
|
77
|
+
# Windows and Linux build with --onefile, which bundles the interpreter, Qt,
|
|
78
|
+
# and the app into a single self-contained executable. PyInstaller's default
|
|
79
|
+
# one-dir mode instead emits the executable next to an _internal/ folder
|
|
80
|
+
# holding the interpreter library (python311.dll / libpython3.11.so), which the
|
|
81
|
+
# launcher resolves relative to its own location — so the moment someone
|
|
82
|
+
# downloads or copies just the executable (e.g. grabbing the single file off
|
|
83
|
+
# the `builds` branch, where GitHub only offers per-file downloads), it dies
|
|
84
|
+
# with "Failed to load Python DLL ...\_internal\python311.dll" or the Linux
|
|
85
|
+
# equivalent. A single file has no such loose ends. Costs a few seconds of
|
|
86
|
+
# startup while it unpacks to a temp dir.
|
|
87
|
+
#
|
|
88
|
+
# macOS stays one-dir, since --windowed there wraps the result in a .app bundle
|
|
89
|
+
# and a bundle is a directory by definition.
|
|
90
|
+
#
|
|
91
|
+
# Both Linux and macOS ship their result as a tarball (see build-linux for the
|
|
92
|
+
# full reasoning). The short version: the artifact pipeline mangles anything it
|
|
93
|
+
# ships loose. actions/upload-artifact zips without preserving Unix modes, and
|
|
94
|
+
# an HTTP download carries no permission metadata at all, so the executable bit
|
|
95
|
+
# is gone by the time a user has the file. macOS additionally needs the archive
|
|
96
|
+
# because upload-artifact follows symlinks: it dereferences every
|
|
97
|
+
# Versions/Current -> Versions/A link inside the Qt frameworks into a second
|
|
98
|
+
# full copy, which both doubles the size and invalidates the _CodeSignature
|
|
99
|
+
# manifest that describes the symlinked layout. tar records modes and symlinks
|
|
100
|
+
# inside the archive, so all of it survives however the archive travelled.
|
|
101
|
+
|
|
102
|
+
build-mac: install-build
|
|
103
|
+
$(PYINSTALLER) --name "$(APP_NAME)" --windowed --noconfirm --clean \
|
|
104
|
+
--icon $(ICON) --add-data "$(ADD_DATA)" --add-data "$(ADD_TUTORIAL)" \
|
|
105
|
+
--distpath $(DIST_DIR)/mac --workpath $(BUILD_DIR)/mac \
|
|
106
|
+
$(ENTRY_POINT)
|
|
107
|
+
chmod +x "$(DIST_DIR)/mac/$(APP_NAME).app/Contents/MacOS/$(APP_NAME)"
|
|
108
|
+
COPYFILE_DISABLE=1 tar -czf $(DIST_DIR)/mac/$(APP_NAME)-mac.tar.gz \
|
|
109
|
+
-C $(DIST_DIR)/mac "$(APP_NAME).app"
|
|
110
|
+
rm -rf "$(DIST_DIR)/mac/$(APP_NAME).app" $(DIST_DIR)/mac/$(APP_NAME)
|
|
111
|
+
|
|
112
|
+
build-windows: install-build
|
|
113
|
+
$(PYINSTALLER) --name "$(APP_NAME)" --windowed --onefile --noconfirm --clean \
|
|
114
|
+
--icon $(ICON) --add-data "$(ADD_DATA)" --add-data "$(ADD_TUTORIAL)" \
|
|
115
|
+
--distpath $(DIST_DIR)/windows --workpath $(BUILD_DIR)/windows \
|
|
116
|
+
$(ENTRY_POINT)
|
|
117
|
+
|
|
118
|
+
# The Linux binary ships as a tarball rather than a bare ELF file, because the
|
|
119
|
+
# executable bit does not survive the trip to a user's machine otherwise. Two
|
|
120
|
+
# separate things strip it: actions/upload-artifact zips without preserving Unix
|
|
121
|
+
# modes (so the `builds` branch ends up with 100644 blobs), and an HTTP download
|
|
122
|
+
# carries no permission metadata at all, so even a 100755 blob lands as 644 when
|
|
123
|
+
# fetched through GitHub's "Download raw file". A non-executable ELF doesn't run
|
|
124
|
+
# — GNOME Files reports "There is no app installed for Executable files" instead
|
|
125
|
+
# of launching it. tar records the mode inside the archive, so extracting yields
|
|
126
|
+
# a binary that is executable no matter how the archive travelled.
|
|
127
|
+
#
|
|
128
|
+
# Only the tarball is left in the dist directory: shipping the loose binary
|
|
129
|
+
# alongside it would just be a broken file for people to download by mistake.
|
|
130
|
+
build-linux: install-build
|
|
131
|
+
$(PYINSTALLER) --name "$(APP_NAME)" --onefile --noconfirm --clean \
|
|
132
|
+
--add-data "$(ADD_DATA)" --add-data "$(ADD_TUTORIAL)" \
|
|
133
|
+
--distpath $(DIST_DIR)/linux --workpath $(BUILD_DIR)/linux \
|
|
134
|
+
$(ENTRY_POINT)
|
|
135
|
+
chmod +x $(DIST_DIR)/linux/$(APP_NAME)
|
|
136
|
+
tar -czf $(DIST_DIR)/linux/$(APP_NAME)-linux.tar.gz \
|
|
137
|
+
-C $(DIST_DIR)/linux $(APP_NAME)
|
|
138
|
+
rm $(DIST_DIR)/linux/$(APP_NAME)
|
|
139
|
+
|
|
140
|
+
# --- PyPI distribution ------------------------------------------------------
|
|
141
|
+
#
|
|
142
|
+
# Unlike the PyInstaller builds above, the sdist and wheel are pure Python and
|
|
143
|
+
# platform-independent, so one machine (or one CI job) produces the artifacts
|
|
144
|
+
# everyone installs; PySide6 is left to pip to resolve per platform. The wheel
|
|
145
|
+
# is built from the sdist so that anything missing from the sdist shows up here
|
|
146
|
+
# rather than in a user's failed `pip install`.
|
|
147
|
+
#
|
|
148
|
+
# The release workflow (.github/workflows/release.yml) runs the same two steps
|
|
149
|
+
# on a version tag and uploads via PyPI trusted publishing, so `make publish` is
|
|
150
|
+
# only needed for a manual release — it prompts for a PyPI API token.
|
|
151
|
+
|
|
152
|
+
dist: install-publish
|
|
153
|
+
rm -rf $(PYPI_DIR)
|
|
154
|
+
$(PYTHON) -m build --outdir $(PYPI_DIR)
|
|
155
|
+
$(VENV_BIN)/twine check --strict $(PYPI_DIR)/*
|
|
156
|
+
|
|
157
|
+
publish-test: dist
|
|
158
|
+
$(VENV_BIN)/twine upload --repository testpypi $(PYPI_DIR)/*
|
|
159
|
+
|
|
160
|
+
publish: dist
|
|
161
|
+
$(VENV_BIN)/twine upload $(PYPI_DIR)/*
|
|
162
|
+
|
|
163
|
+
# Convenience: build for whatever OS `make` is currently running on.
|
|
164
|
+
UNAME_S := $(shell uname -s 2>/dev/null)
|
|
165
|
+
ifeq ($(OS),Windows_NT)
|
|
166
|
+
build: build-windows
|
|
167
|
+
else ifeq ($(UNAME_S),Darwin)
|
|
168
|
+
build: build-mac
|
|
169
|
+
else
|
|
170
|
+
build: build-linux
|
|
171
|
+
endif
|
openansho-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: openansho
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Open-source qualitative data analysis
|
|
5
|
+
Project-URL: Homepage, https://github.com/zdelrosario/open-ansho
|
|
6
|
+
Project-URL: Repository, https://github.com/zdelrosario/open-ansho
|
|
7
|
+
Project-URL: Issues, https://github.com/zdelrosario/open-ansho/issues
|
|
8
|
+
Author-email: Zachary del Rosario <zdelrosario@olin.edu>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: codebook,coding,qda,qualitative-data-analysis,research,vim
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: MacOS X
|
|
14
|
+
Classifier: Environment :: Win32 (MS Windows)
|
|
15
|
+
Classifier: Environment :: X11 Applications :: Qt
|
|
16
|
+
Classifier: Intended Audience :: Education
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: Operating System :: MacOS
|
|
19
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
20
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
28
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
29
|
+
Requires-Python: >=3.9
|
|
30
|
+
Requires-Dist: pyside6>=6.6
|
|
31
|
+
Provides-Extra: build
|
|
32
|
+
Requires-Dist: pillow; extra == 'build'
|
|
33
|
+
Requires-Dist: pyinstaller>=6.0; extra == 'build'
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest-qt>=4.4; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
37
|
+
Provides-Extra: publish
|
|
38
|
+
Requires-Dist: build>=1.2; extra == 'publish'
|
|
39
|
+
Requires-Dist: twine>=6.1; extra == 'publish'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# Open Ansho (暗証) - Open-source qualitative data analysis
|
|
43
|
+
|
|
44
|
+
Open Ansho is a free and open-source desktop app for qualitative data analysis of text documents. This was designed as a fast and focused tool with the following goals:
|
|
45
|
+
|
|
46
|
+
- Fast coding: By using Vim-inspired keybindings, you can code a document without ever moving your hands off the keyboard.
|
|
47
|
+
- Easy collaboration: No signup needed. All data (text and codes) are written to a database file that you can store in a shared directory (e.g., Dropbox, Google Drive, OneDrive).
|
|
48
|
+
- Clarity: Visually compare overlapping code segments through vertically-separated split highlights. Easily see simultaneous coding through striped segments.
|
|
49
|
+
- Lightweight: No bloat. Just fast coding.
|
|
50
|
+
|
|
51
|
+
Documents can be imported as plain text (`.txt`) or Microsoft Word (`.docx`) files; Word documents are converted to plain text on import, one line per paragraph.
|
|
52
|
+
|
|
53
|
+
The app opens on a built-in tutorial that walks you through coding your first document, so there is nothing to set up before trying it. The tutorial is a scratch project held in memory — code it up however you like, then use File > New Project when you're ready to work on your own data. Nothing from the tutorial is saved, so it starts fresh every time you open the app (File > Open Tutorial brings it back mid-session).
|
|
54
|
+
|
|
55
|
+
This software was created using Claude Code.
|
|
56
|
+
|
|
57
|
+
## Download and Run
|
|
58
|
+
|
|
59
|
+
Prebuilt executables for macOS, Windows, and Linux are published on the [`builds` branch](https://github.com/zdelrosario/open-ansho/tree/builds/runs). Each build lives in its own folder named `<run number>-<commit>`; open the highest-numbered one for the most recent build, then the folder for your operating system.
|
|
60
|
+
|
|
61
|
+
The app is fully self-contained — there is nothing to install, and no Python needed. On Windows and Linux, expect a few seconds of delay every time you start it: those builds are a single file that unpacks itself to a temporary directory on each launch. The macOS app is a normal bundle and starts without that pause.
|
|
62
|
+
|
|
63
|
+
These builds are not code-signed, so each operating system will warn you the first time you open one. The steps below include how to get past that. If you would rather not click through a security warning, run from source instead — see [Development Setup](#development-setup).
|
|
64
|
+
|
|
65
|
+
> **Tip:** OpenAnsho remembers your username in a `.openansho_user` file it writes alongside the executable (inside the app bundle, on macOS). Put the app somewhere permanent and writable — `~/Applications` on macOS, a folder under your user account such as `C:\Users\<you>\Apps` on Windows — rather than leaving it in `Downloads`. Avoid `C:\Program Files`, which a standard account cannot write to. Replacing the app with a newer build starts you over with a fresh username file.
|
|
66
|
+
|
|
67
|
+
### Windows
|
|
68
|
+
|
|
69
|
+
1. Download `OpenAnsho.exe` from the `windows` folder.
|
|
70
|
+
2. Double-click it.
|
|
71
|
+
3. Windows SmartScreen will likely say it "protected your PC". Click **More info**, then **Run anyway**.
|
|
72
|
+
|
|
73
|
+
### macOS
|
|
74
|
+
|
|
75
|
+
1. Download `OpenAnsho-mac.tar.gz` from the `mac` folder.
|
|
76
|
+
2. Double-click the archive to extract `OpenAnsho.app`, then drag it to your Applications folder.
|
|
77
|
+
3. Double-click the app. macOS will refuse to open it, saying the developer cannot be verified.
|
|
78
|
+
4. Open **System Settings → Privacy & Security**, scroll to the Security section, and click **Open Anyway** next to the message about OpenAnsho. Confirm once more when prompted.
|
|
79
|
+
|
|
80
|
+
You only need to do step 4 once. On older versions of macOS you can instead right-click the app and choose **Open**, which offers an **Open** button in the warning dialog; recent versions have removed that shortcut for unsigned apps in favor of the Privacy & Security panel.
|
|
81
|
+
|
|
82
|
+
### Linux
|
|
83
|
+
|
|
84
|
+
1. Download `OpenAnsho-linux.tar.gz` from the `linux` folder.
|
|
85
|
+
2. Extract it and run the binary:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
tar -xzf OpenAnsho-linux.tar.gz
|
|
89
|
+
./OpenAnsho
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The binary inside the archive is already marked executable, so no `chmod` is needed. Extract it with `tar` rather than dragging it out of an archive viewer, since some viewers drop file permissions — if you end up with a file that won't start, `chmod +x OpenAnsho` restores it.
|
|
93
|
+
|
|
94
|
+
The Linux build is produced on the current Ubuntu CI image, so it needs a reasonably recent glibc and will not run on notably older distributions. It also unpacks itself into `/tmp` at startup, which fails on systems that mount `/tmp` with `noexec`; setting `TMPDIR` to a directory that permits execution works around that.
|
|
95
|
+
|
|
96
|
+
## Install with pip
|
|
97
|
+
|
|
98
|
+
If you already have Python 3.9 or newer, OpenAnsho is also on PyPI:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install openansho
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Then start it from a terminal:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
openansho
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`pipx install openansho` works too, and is the better choice if you would rather not add OpenAnsho (and Qt, which comes with it) to an existing environment — pipx keeps it in its own virtualenv while still putting the `openansho` command on your PATH.
|
|
111
|
+
|
|
112
|
+
The pip install pulls in PySide6, which ships Qt itself; on a minimal Linux install you may still need a few system libraries (`libegl1`, `libgl1`, `libxkbcommon0`, `libxcb-cursor0` on Debian/Ubuntu). Unlike the prebuilt executables above, a pip install stores your username in a per-user config directory (`~/Library/Application Support/OpenAnsho` on macOS, `%APPDATA%\OpenAnsho` on Windows, `~/.config/openansho` on Linux), so it survives upgrading the package.
|
|
113
|
+
|
|
114
|
+
If the app fails to start and you want to see why, run `python -m openansho` instead — that form keeps a console attached on Windows and prints the traceback.
|
|
115
|
+
|
|
116
|
+
## Development Setup
|
|
117
|
+
|
|
118
|
+
First-time setup, run once from the repo root:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
python3 -m venv .venv # create the project virtualenv
|
|
122
|
+
source .venv/bin/activate # activate it
|
|
123
|
+
pip install -e ".[dev]" # install package + dev deps (pytest, pytest-qt)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Every subsequent session, activate the virtualenv before running any commands below:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
source .venv/bin/activate # activate the project virtualenv
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
To run the development version of the app (with the virtualenv active):
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
python -m openansho # run the app (or the `openansho` console script)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Learning Vim
|
|
139
|
+
|
|
140
|
+
While the app can be used using traditional controls (mouse and keyboard), you'll get the most out of Open Ansho if you learn how to navigate using Vim keybindings. There are a variety of interactive tutorials for learning Vim, such as [VimHero](https://www.vim-hero.com/), [VIM Adventures](https://vim-adventures.com/), and [OpenVim](https://openvim.com/).
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Open Ansho (暗証) - Open-source qualitative data analysis
|
|
2
|
+
|
|
3
|
+
Open Ansho is a free and open-source desktop app for qualitative data analysis of text documents. This was designed as a fast and focused tool with the following goals:
|
|
4
|
+
|
|
5
|
+
- Fast coding: By using Vim-inspired keybindings, you can code a document without ever moving your hands off the keyboard.
|
|
6
|
+
- Easy collaboration: No signup needed. All data (text and codes) are written to a database file that you can store in a shared directory (e.g., Dropbox, Google Drive, OneDrive).
|
|
7
|
+
- Clarity: Visually compare overlapping code segments through vertically-separated split highlights. Easily see simultaneous coding through striped segments.
|
|
8
|
+
- Lightweight: No bloat. Just fast coding.
|
|
9
|
+
|
|
10
|
+
Documents can be imported as plain text (`.txt`) or Microsoft Word (`.docx`) files; Word documents are converted to plain text on import, one line per paragraph.
|
|
11
|
+
|
|
12
|
+
The app opens on a built-in tutorial that walks you through coding your first document, so there is nothing to set up before trying it. The tutorial is a scratch project held in memory — code it up however you like, then use File > New Project when you're ready to work on your own data. Nothing from the tutorial is saved, so it starts fresh every time you open the app (File > Open Tutorial brings it back mid-session).
|
|
13
|
+
|
|
14
|
+
This software was created using Claude Code.
|
|
15
|
+
|
|
16
|
+
## Download and Run
|
|
17
|
+
|
|
18
|
+
Prebuilt executables for macOS, Windows, and Linux are published on the [`builds` branch](https://github.com/zdelrosario/open-ansho/tree/builds/runs). Each build lives in its own folder named `<run number>-<commit>`; open the highest-numbered one for the most recent build, then the folder for your operating system.
|
|
19
|
+
|
|
20
|
+
The app is fully self-contained — there is nothing to install, and no Python needed. On Windows and Linux, expect a few seconds of delay every time you start it: those builds are a single file that unpacks itself to a temporary directory on each launch. The macOS app is a normal bundle and starts without that pause.
|
|
21
|
+
|
|
22
|
+
These builds are not code-signed, so each operating system will warn you the first time you open one. The steps below include how to get past that. If you would rather not click through a security warning, run from source instead — see [Development Setup](#development-setup).
|
|
23
|
+
|
|
24
|
+
> **Tip:** OpenAnsho remembers your username in a `.openansho_user` file it writes alongside the executable (inside the app bundle, on macOS). Put the app somewhere permanent and writable — `~/Applications` on macOS, a folder under your user account such as `C:\Users\<you>\Apps` on Windows — rather than leaving it in `Downloads`. Avoid `C:\Program Files`, which a standard account cannot write to. Replacing the app with a newer build starts you over with a fresh username file.
|
|
25
|
+
|
|
26
|
+
### Windows
|
|
27
|
+
|
|
28
|
+
1. Download `OpenAnsho.exe` from the `windows` folder.
|
|
29
|
+
2. Double-click it.
|
|
30
|
+
3. Windows SmartScreen will likely say it "protected your PC". Click **More info**, then **Run anyway**.
|
|
31
|
+
|
|
32
|
+
### macOS
|
|
33
|
+
|
|
34
|
+
1. Download `OpenAnsho-mac.tar.gz` from the `mac` folder.
|
|
35
|
+
2. Double-click the archive to extract `OpenAnsho.app`, then drag it to your Applications folder.
|
|
36
|
+
3. Double-click the app. macOS will refuse to open it, saying the developer cannot be verified.
|
|
37
|
+
4. Open **System Settings → Privacy & Security**, scroll to the Security section, and click **Open Anyway** next to the message about OpenAnsho. Confirm once more when prompted.
|
|
38
|
+
|
|
39
|
+
You only need to do step 4 once. On older versions of macOS you can instead right-click the app and choose **Open**, which offers an **Open** button in the warning dialog; recent versions have removed that shortcut for unsigned apps in favor of the Privacy & Security panel.
|
|
40
|
+
|
|
41
|
+
### Linux
|
|
42
|
+
|
|
43
|
+
1. Download `OpenAnsho-linux.tar.gz` from the `linux` folder.
|
|
44
|
+
2. Extract it and run the binary:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
tar -xzf OpenAnsho-linux.tar.gz
|
|
48
|
+
./OpenAnsho
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The binary inside the archive is already marked executable, so no `chmod` is needed. Extract it with `tar` rather than dragging it out of an archive viewer, since some viewers drop file permissions — if you end up with a file that won't start, `chmod +x OpenAnsho` restores it.
|
|
52
|
+
|
|
53
|
+
The Linux build is produced on the current Ubuntu CI image, so it needs a reasonably recent glibc and will not run on notably older distributions. It also unpacks itself into `/tmp` at startup, which fails on systems that mount `/tmp` with `noexec`; setting `TMPDIR` to a directory that permits execution works around that.
|
|
54
|
+
|
|
55
|
+
## Install with pip
|
|
56
|
+
|
|
57
|
+
If you already have Python 3.9 or newer, OpenAnsho is also on PyPI:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install openansho
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Then start it from a terminal:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
openansho
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`pipx install openansho` works too, and is the better choice if you would rather not add OpenAnsho (and Qt, which comes with it) to an existing environment — pipx keeps it in its own virtualenv while still putting the `openansho` command on your PATH.
|
|
70
|
+
|
|
71
|
+
The pip install pulls in PySide6, which ships Qt itself; on a minimal Linux install you may still need a few system libraries (`libegl1`, `libgl1`, `libxkbcommon0`, `libxcb-cursor0` on Debian/Ubuntu). Unlike the prebuilt executables above, a pip install stores your username in a per-user config directory (`~/Library/Application Support/OpenAnsho` on macOS, `%APPDATA%\OpenAnsho` on Windows, `~/.config/openansho` on Linux), so it survives upgrading the package.
|
|
72
|
+
|
|
73
|
+
If the app fails to start and you want to see why, run `python -m openansho` instead — that form keeps a console attached on Windows and prints the traceback.
|
|
74
|
+
|
|
75
|
+
## Development Setup
|
|
76
|
+
|
|
77
|
+
First-time setup, run once from the repo root:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
python3 -m venv .venv # create the project virtualenv
|
|
81
|
+
source .venv/bin/activate # activate it
|
|
82
|
+
pip install -e ".[dev]" # install package + dev deps (pytest, pytest-qt)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Every subsequent session, activate the virtualenv before running any commands below:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
source .venv/bin/activate # activate the project virtualenv
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
To run the development version of the app (with the virtualenv active):
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
python -m openansho # run the app (or the `openansho` console script)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Learning Vim
|
|
98
|
+
|
|
99
|
+
While the app can be used using traditional controls (mouse and keyboard), you'll get the most out of Open Ansho if you learn how to navigate using Vim keybindings. There are a variety of interactive tutorials for learning Vim, such as [VimHero](https://www.vim-hero.com/), [VIM Adventures](https://vim-adventures.com/), and [OpenVim](https://openvim.com/).
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg width="100%" viewBox="0 0 680 680" xmlns="http://www.w3.org/2000/svg" role="img" style="">
|
|
2
|
+
<title style="fill:rgb(0, 0, 0);stroke:none;color:rgb(11, 11, 11);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto">Minimalist app icon featuring the kanji 証</title>
|
|
3
|
+
<desc style="fill:rgb(0, 0, 0);stroke:none;color:rgb(11, 11, 11);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto">A rounded-square app icon with a deep navy background and the kanji character 証, meaning proof or certificate, centered in cream, with a small red seal accent in the corner.</desc>
|
|
4
|
+
<rect x="40" y="40" width="600" height="600" rx="140" fill="#1c2b45" style="fill:rgb(28, 43, 69);stroke:none;color:rgb(11, 11, 11);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
5
|
+
<rect x="88" y="88" width="504" height="504" rx="100" fill="none" stroke="#f2ead9" stroke-width="2" opacity="0.35" style="fill:none;stroke:rgb(242, 234, 217);color:rgb(11, 11, 11);stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.35;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
6
|
+
<text x="340" y="365" text-anchor="middle" dominant-baseline="central" font-family="'Hiragino Mincho ProN','Noto Serif JP',serif" font-size="360" font-weight="400" fill="#f2ead9" style="fill:rgb(242, 234, 217);stroke:none;color:rgb(11, 11, 11);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Hiragino Mincho ProN", "Noto Serif JP", serif;font-size:360px;font-weight:400;text-anchor:middle;dominant-baseline:central">証</text>
|
|
7
|
+
<circle cx="520" cy="520" r="46" fill="none" stroke="#c1443a" stroke-width="10" style="fill:none;stroke:rgb(193, 68, 58);color:rgb(11, 11, 11);stroke-width:10px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
8
|
+
<circle cx="520" cy="520" r="8" fill="#c1443a" style="fill:rgb(193, 68, 58);stroke:none;color:rgb(11, 11, 11);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
9
|
+
</svg>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
# 1.27 is the first hatchling that understands PEP 639 (`license`/`license-files`).
|
|
3
|
+
requires = ["hatchling>=1.27"]
|
|
4
|
+
build-backend = "hatchling.build"
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "openansho"
|
|
8
|
+
dynamic = ["version"]
|
|
9
|
+
description = "Open-source qualitative data analysis"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
requires-python = ">=3.9"
|
|
14
|
+
authors = [{ name = "Zachary del Rosario", email = "zdelrosario@olin.edu" }]
|
|
15
|
+
keywords = [
|
|
16
|
+
"qualitative-data-analysis",
|
|
17
|
+
"qda",
|
|
18
|
+
"coding",
|
|
19
|
+
"codebook",
|
|
20
|
+
"research",
|
|
21
|
+
"vim",
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 3 - Alpha",
|
|
25
|
+
"Environment :: MacOS X",
|
|
26
|
+
"Environment :: Win32 (MS Windows)",
|
|
27
|
+
"Environment :: X11 Applications :: Qt",
|
|
28
|
+
"Intended Audience :: Education",
|
|
29
|
+
"Intended Audience :: Science/Research",
|
|
30
|
+
"Operating System :: MacOS",
|
|
31
|
+
"Operating System :: Microsoft :: Windows",
|
|
32
|
+
"Operating System :: POSIX :: Linux",
|
|
33
|
+
"Programming Language :: Python :: 3",
|
|
34
|
+
"Programming Language :: Python :: 3.9",
|
|
35
|
+
"Programming Language :: Python :: 3.10",
|
|
36
|
+
"Programming Language :: Python :: 3.11",
|
|
37
|
+
"Programming Language :: Python :: 3.12",
|
|
38
|
+
"Programming Language :: Python :: 3.13",
|
|
39
|
+
"Topic :: Scientific/Engineering :: Information Analysis",
|
|
40
|
+
"Topic :: Text Processing :: Linguistic",
|
|
41
|
+
]
|
|
42
|
+
dependencies = [
|
|
43
|
+
"PySide6>=6.6",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Homepage = "https://github.com/zdelrosario/open-ansho"
|
|
48
|
+
Repository = "https://github.com/zdelrosario/open-ansho"
|
|
49
|
+
Issues = "https://github.com/zdelrosario/open-ansho/issues"
|
|
50
|
+
|
|
51
|
+
[project.optional-dependencies]
|
|
52
|
+
dev = [
|
|
53
|
+
"pytest>=8.0",
|
|
54
|
+
"pytest-qt>=4.4",
|
|
55
|
+
]
|
|
56
|
+
build = [
|
|
57
|
+
"pyinstaller>=6.0",
|
|
58
|
+
"pillow",
|
|
59
|
+
]
|
|
60
|
+
# Building and uploading the sdist/wheel to PyPI (see `make dist` / `make publish`).
|
|
61
|
+
publish = [
|
|
62
|
+
"build>=1.2",
|
|
63
|
+
"twine>=6.1",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
# A gui-script rather than a console script: on Windows the launcher is built
|
|
67
|
+
# against pythonw, so double-clicking or running `openansho` doesn't leave a
|
|
68
|
+
# console window sitting behind the app. On macOS/Linux the two kinds of entry
|
|
69
|
+
# point are identical. `python -m openansho` still runs it with a console
|
|
70
|
+
# attached, which is the way to see a traceback on Windows.
|
|
71
|
+
[project.gui-scripts]
|
|
72
|
+
openansho = "openansho.__main__:main"
|
|
73
|
+
|
|
74
|
+
[tool.hatch.version]
|
|
75
|
+
path = "src/openansho/__init__.py"
|
|
76
|
+
|
|
77
|
+
[tool.hatch.build.targets.wheel]
|
|
78
|
+
packages = ["src/openansho"]
|
|
79
|
+
|
|
80
|
+
# The app icon lives at the repo root for PyInstaller's sake (see the Makefile),
|
|
81
|
+
# but an installed copy has no repo around it — so ship the icon inside the
|
|
82
|
+
# package too, where `__main__._icon_path` looks for it.
|
|
83
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
84
|
+
"images/kanji_shou_app_icon.png" = "openansho/kanji_shou_app_icon.png"
|
|
85
|
+
|
|
86
|
+
[tool.hatch.build.targets.sdist]
|
|
87
|
+
include = [
|
|
88
|
+
"/src",
|
|
89
|
+
"/tests",
|
|
90
|
+
"/images",
|
|
91
|
+
"/Makefile",
|
|
92
|
+
"/README.md",
|
|
93
|
+
"/CLAUDE.md",
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
[tool.pytest.ini_options]
|
|
97
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|