everyome 0.1.0a1__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.
- everyome-0.1.0a1/CITATION.cff +11 -0
- everyome-0.1.0a1/LICENSE +21 -0
- everyome-0.1.0a1/MANIFEST.in +3 -0
- everyome-0.1.0a1/PKG-INFO +121 -0
- everyome-0.1.0a1/README.md +67 -0
- everyome-0.1.0a1/THIRD_PARTY_NOTICES.md +15 -0
- everyome-0.1.0a1/everyome/__init__.py +2 -0
- everyome-0.1.0a1/everyome/__main__.py +30 -0
- everyome-0.1.0a1/everyome/core/__init__.py +1 -0
- everyome-0.1.0a1/everyome/core/backends.py +166 -0
- everyome-0.1.0a1/everyome/core/demo/__init__.py +38 -0
- everyome-0.1.0a1/everyome/core/demo/fake_slurm.py +151 -0
- everyome-0.1.0a1/everyome/core/engine.py +78 -0
- everyome-0.1.0a1/everyome/core/manifest.py +301 -0
- everyome-0.1.0a1/everyome/core/modules.py +38 -0
- everyome-0.1.0a1/everyome/core/nfschema.py +69 -0
- everyome-0.1.0a1/everyome/core/projects.py +51 -0
- everyome-0.1.0a1/everyome/core/records.py +277 -0
- everyome-0.1.0a1/everyome/core/rerun.py +114 -0
- everyome-0.1.0a1/everyome/core/runs.py +169 -0
- everyome-0.1.0a1/everyome/core/server.py +512 -0
- everyome-0.1.0a1/everyome/core/session.py +113 -0
- everyome-0.1.0a1/everyome/core/sessions.py +68 -0
- everyome-0.1.0a1/everyome/core/slurm.py +62 -0
- everyome-0.1.0a1/everyome/core/suites.py +74 -0
- everyome-0.1.0a1/everyome/modules/__init__.py +1 -0
- everyome-0.1.0a1/everyome/modules/rna/__init__.py +1 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/__init__.py +1 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/demo_data.py +55 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/demo_pipeline.py +54 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/docs/manual.md +77 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/engine.py +191 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/helpers.py +68 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/methods.py +39 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/module.yaml +84 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/pipeline/LICENSE-nf-core-rnaseq +21 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/pipeline/README.md +9 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/pipeline/nextflow_schema.json +1063 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/pipeline/schema_input.json +72 -0
- everyome-0.1.0a1/everyome/modules/rna/bulk_de/ui.js +168 -0
- everyome-0.1.0a1/everyome/modules/singlecell/__init__.py +1 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/__init__.py +1 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/demo_data.py +135 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/docs/manual.md +94 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/docs/playground/UMAP-JS-LICENSE +202 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/docs/playground/play_core.js +237 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/docs/playground/play_ui.js +295 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/docs/playground/umap-js.min.js +1 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/engine.py +371 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/helpers.py +70 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/methods.py +90 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/mock_stage.py +71 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/module.yaml +159 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/stage.py +82 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/templates/cluster_identities_template.xlsx +0 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/templates/round1_barcodes_template.xlsx +0 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/ui.js +298 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/workflow/python/10_label_cells.py +114 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/workflow/python/11_qc_filter.py +56 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/workflow/python/12_integrate_cluster.py +85 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/workflow/python/13_marker_plots.py +92 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/workflow/python/14_marker_reports.py +196 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/workflow/python/15_annotate_clusters.py +115 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/workflow/python/common.py +121 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/workflow/reads/01_read_preprocessing.sh +101 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/workflow/reads/02_align_merge_dge.sh +98 -0
- everyome-0.1.0a1/everyome/modules/singlecell/splitseq/workflow/reads/common.sh +57 -0
- everyome-0.1.0a1/everyome/modules/tutorial/__init__.py +1 -0
- everyome-0.1.0a1/everyome/modules/tutorial/sequence_summary/__init__.py +1 -0
- everyome-0.1.0a1/everyome/modules/tutorial/sequence_summary/demo/sequences.fasta +366 -0
- everyome-0.1.0a1/everyome/modules/tutorial/sequence_summary/docs/manual.md +37 -0
- everyome-0.1.0a1/everyome/modules/tutorial/sequence_summary/engine.py +77 -0
- everyome-0.1.0a1/everyome/modules/tutorial/sequence_summary/module.yaml +67 -0
- everyome-0.1.0a1/everyome/modules/tutorial/sequence_summary/steps.py +73 -0
- everyome-0.1.0a1/everyome/modules/tutorial/sequence_summary/ui.js +43 -0
- everyome-0.1.0a1/everyome/static/app.css +272 -0
- everyome-0.1.0a1/everyome/static/app.js +824 -0
- everyome-0.1.0a1/everyome/static/fonts/albert-sans-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/albert-sans-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/albert-sans-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/albert-sans-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/albert-sans-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/albert-sans-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/albert-sans-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/albert-sans-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/albert-sans-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-sans-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-sans-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-sans-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-sans-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-sans-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-sans-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/alegreya-sans-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/archivo-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/archivo-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/archivo-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/archivo-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/archivo-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/archivo-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/archivo-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/archivo-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/archivo-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/barlow-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/barlow-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/barlow-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/barlow-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/barlow-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/barlow-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/barlow-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/barlow-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/barlow-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bodoni-moda-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/bodoni-moda-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bodoni-moda-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bodoni-moda-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bodoni-moda-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bodoni-moda-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bodoni-moda-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bodoni-moda-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bodoni-moda-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bricolage-grotesque-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/bricolage-grotesque-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bricolage-grotesque-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bricolage-grotesque-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/bricolage-grotesque-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/chivo-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/chivo-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/chivo-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/chivo-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/chivo-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/chivo-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/chivo-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/chivo-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/chivo-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/cormorant-garamond-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/cormorant-garamond-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/cormorant-garamond-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/cormorant-garamond-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/cormorant-garamond-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/cormorant-garamond-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/cormorant-garamond-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/cormorant-garamond-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/cormorant-garamond-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/crimson-pro-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/crimson-pro-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/crimson-pro-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/crimson-pro-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/crimson-pro-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/crimson-pro-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/crimson-pro-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/crimson-pro-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/crimson-pro-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-sans-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-sans-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-sans-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-sans-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-sans-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-sans-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-sans-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-sans-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-sans-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-serif-display-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-serif-display-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/dm-serif-display-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/eb-garamond-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/eb-garamond-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/eb-garamond-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/eb-garamond-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/eb-garamond-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/eb-garamond-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/eb-garamond-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/eb-garamond-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/eb-garamond-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/epilogue-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/epilogue-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/epilogue-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/epilogue-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/epilogue-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/epilogue-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/epilogue-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/epilogue-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/epilogue-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/exo-2-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/exo-2-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/exo-2-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/exo-2-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/exo-2-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/exo-2-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/exo-2-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/exo-2-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/exo-2-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/figtree-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/figtree-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/figtree-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/figtree-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/figtree-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/figtree-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/figtree-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/figtree-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/figtree-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/fonts.css +357 -0
- everyome-0.1.0a1/everyome/static/fonts/fraunces-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/fraunces-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/fraunces-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/fraunces-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/fraunces-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/fraunces-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/fraunces-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/fraunces-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/fraunces-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/gloock-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/gloock-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/hanken-grotesk-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/hanken-grotesk-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/hanken-grotesk-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/hanken-grotesk-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/hanken-grotesk-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/hanken-grotesk-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/hanken-grotesk-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/hanken-grotesk-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/hanken-grotesk-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-mono-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-mono-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-mono-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-mono-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-mono-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-mono-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-sans-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-sans-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-sans-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-sans-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-sans-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-sans-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-serif-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-serif-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-serif-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-serif-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-serif-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-serif-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-serif-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-serif-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/ibm-plex-serif-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-sans-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-sans-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-sans-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-sans-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-sans-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-sans-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-sans-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-sans-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-sans-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-serif-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-serif-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/instrument-serif-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jetbrains-mono-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/jetbrains-mono-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jetbrains-mono-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jetbrains-mono-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jetbrains-mono-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jetbrains-mono-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jetbrains-mono-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/josefin-sans-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/josefin-sans-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/josefin-sans-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/josefin-sans-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/josefin-sans-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/josefin-sans-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/josefin-sans-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/josefin-sans-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/josefin-sans-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jost-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/jost-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jost-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jost-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jost-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jost-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jost-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jost-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/jost-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/karla-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/karla-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/karla-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/karla-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/karla-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/karla-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/karla-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/karla-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/karla-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lexend-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/lexend-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lexend-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lexend-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lexend-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/libre-baskerville-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/libre-baskerville-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/libre-baskerville-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/libre-baskerville-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/libre-baskerville-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/libre-baskerville-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/libre-baskerville-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/libre-baskerville-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/libre-baskerville-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lora-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/lora-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lora-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lora-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lora-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lora-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lora-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lora-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/lora-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/manrope-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/manrope-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/manrope-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/manrope-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/manrope-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/newsreader-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/newsreader-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/newsreader-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/newsreader-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/newsreader-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/newsreader-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/newsreader-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/newsreader-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/newsreader-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/nunito-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/nunito-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/nunito-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/nunito-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/nunito-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/nunito-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/nunito-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/nunito-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/nunito-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/onest-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/onest-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/onest-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/onest-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/onest-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/outfit-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/outfit-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/outfit-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/outfit-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/outfit-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/playfair-display-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/playfair-display-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/playfair-display-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/playfair-display-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/playfair-display-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/playfair-display-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/playfair-display-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/playfair-display-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/playfair-display-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/plus-jakarta-sans-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/plus-jakarta-sans-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/plus-jakarta-sans-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/plus-jakarta-sans-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/plus-jakarta-sans-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/plus-jakarta-sans-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/plus-jakarta-sans-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/plus-jakarta-sans-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/plus-jakarta-sans-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/quicksand-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/quicksand-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/quicksand-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/quicksand-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/quicksand-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/raleway-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/raleway-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/raleway-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/raleway-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/raleway-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/raleway-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/raleway-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/raleway-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/raleway-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-display-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-display-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-display-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-display-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-display-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-display-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-display-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-display-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-display-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-text-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-text-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-text-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-text-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-text-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-text-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-text-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-text-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/red-hat-text-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/rubik-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/rubik-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/rubik-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/rubik-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/rubik-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/rubik-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/rubik-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/rubik-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/rubik-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/schibsted-grotesk-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/schibsted-grotesk-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/schibsted-grotesk-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/schibsted-grotesk-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/schibsted-grotesk-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/schibsted-grotesk-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/schibsted-grotesk-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/schibsted-grotesk-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/schibsted-grotesk-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/sora-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/sora-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/sora-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/sora-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/sora-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/source-serif-4-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/source-serif-4-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/source-serif-4-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/source-serif-4-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/source-serif-4-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/source-serif-4-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/source-serif-4-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/source-serif-4-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/source-serif-4-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/space-grotesk-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/space-grotesk-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/space-grotesk-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/space-grotesk-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/space-grotesk-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/spectral-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/spectral-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/spectral-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/spectral-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/spectral-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/spectral-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/spectral-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/spectral-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/spectral-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/syne-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/syne-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/syne-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/syne-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/syne-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/unbounded-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/unbounded-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/unbounded-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/unbounded-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/unbounded-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/urbanist-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/urbanist-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/urbanist-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/urbanist-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/urbanist-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/urbanist-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/urbanist-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/urbanist-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/urbanist-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/work-sans-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/work-sans-latin-400-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/work-sans-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/work-sans-latin-500-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/work-sans-latin-500-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/work-sans-latin-600-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/work-sans-latin-600-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/work-sans-latin-700-italic.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/work-sans-latin-700-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/fonts/young-serif-LICENSE +93 -0
- everyome-0.1.0a1/everyome/static/fonts/young-serif-latin-400-normal.woff2 +0 -0
- everyome-0.1.0a1/everyome/static/index.html +41 -0
- everyome-0.1.0a1/everyome/static/themes.json +1 -0
- everyome-0.1.0a1/everyome/suites.yaml +92 -0
- everyome-0.1.0a1/everyome.egg-info/PKG-INFO +121 -0
- everyome-0.1.0a1/everyome.egg-info/SOURCES.txt +505 -0
- everyome-0.1.0a1/everyome.egg-info/dependency_links.txt +1 -0
- everyome-0.1.0a1/everyome.egg-info/entry_points.txt +2 -0
- everyome-0.1.0a1/everyome.egg-info/requires.txt +31 -0
- everyome-0.1.0a1/everyome.egg-info/top_level.txt +1 -0
- everyome-0.1.0a1/pyproject.toml +57 -0
- everyome-0.1.0a1/setup.cfg +4 -0
- everyome-0.1.0a1/tests/rerun_helpers.py +23 -0
- everyome-0.1.0a1/tests/test_bulk_rna_flow.py +127 -0
- everyome-0.1.0a1/tests/test_demo_flow.py +99 -0
- everyome-0.1.0a1/tests/test_manifest.py +70 -0
- everyome-0.1.0a1/tests/test_nextflow.py +72 -0
- everyome-0.1.0a1/tests/test_slurm.py +12 -0
- everyome-0.1.0a1/tests/test_smoke.py +24 -0
- everyome-0.1.0a1/tests/test_splitseq_flow.py +169 -0
- everyome-0.1.0a1/tests/test_suites.py +63 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use Everyome, adapt its code, or reuse its text or figures, please cite it as below."
|
|
3
|
+
title: "Everyome: every -ome, for everyone"
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: Horkan
|
|
7
|
+
given-names: Helen R.
|
|
8
|
+
affiliation: Stowers Institute for Medical Research
|
|
9
|
+
version: 0.1.0a1
|
|
10
|
+
license: MIT
|
|
11
|
+
repository-code: "https://github.com/Everyome/everyome"
|
everyome-0.1.0a1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Helen R Horkan
|
|
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.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: everyome
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: Every -ome, for everyone: omics analysis with a simple interface and every setting in reach, on your own computer or Slurm cluster.
|
|
5
|
+
Author: Helen R Horkan
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Everyome/everyome
|
|
8
|
+
Project-URL: Source, https://github.com/Everyome/everyome
|
|
9
|
+
Project-URL: Issues, https://github.com/Everyome/everyome/issues
|
|
10
|
+
Project-URL: Citation, https://github.com/Everyome/everyome/blob/main/CITATION.cff
|
|
11
|
+
Keywords: bioinformatics,omics,single-cell,SPLiT-seq,RNA-seq,differential expression,Slurm,Nextflow,GUI
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Operating System :: MacOS
|
|
20
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
21
|
+
Classifier: Framework :: FastAPI
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
License-File: THIRD_PARTY_NOTICES.md
|
|
26
|
+
Requires-Dist: fastapi>=0.100
|
|
27
|
+
Requires-Dist: uvicorn>=0.23
|
|
28
|
+
Requires-Dist: httpx<1,>=0.24
|
|
29
|
+
Requires-Dist: python-multipart
|
|
30
|
+
Requires-Dist: pyyaml
|
|
31
|
+
Requires-Dist: setproctitle
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: pytest; extra == "test"
|
|
34
|
+
Provides-Extra: singlecell
|
|
35
|
+
Requires-Dist: numpy; extra == "singlecell"
|
|
36
|
+
Requires-Dist: pandas; extra == "singlecell"
|
|
37
|
+
Requires-Dist: scipy; extra == "singlecell"
|
|
38
|
+
Requires-Dist: scanpy>=1.9; extra == "singlecell"
|
|
39
|
+
Requires-Dist: anndata>=0.9; extra == "singlecell"
|
|
40
|
+
Requires-Dist: harmonypy; extra == "singlecell"
|
|
41
|
+
Requires-Dist: leidenalg; extra == "singlecell"
|
|
42
|
+
Requires-Dist: igraph; extra == "singlecell"
|
|
43
|
+
Requires-Dist: openpyxl; extra == "singlecell"
|
|
44
|
+
Requires-Dist: seaborn; extra == "singlecell"
|
|
45
|
+
Requires-Dist: matplotlib; extra == "singlecell"
|
|
46
|
+
Provides-Extra: rna
|
|
47
|
+
Requires-Dist: numpy; extra == "rna"
|
|
48
|
+
Requires-Dist: pandas; extra == "rna"
|
|
49
|
+
Requires-Dist: matplotlib; extra == "rna"
|
|
50
|
+
Requires-Dist: pydeseq2; extra == "rna"
|
|
51
|
+
Provides-Extra: all
|
|
52
|
+
Requires-Dist: everyome[rna,singlecell]; extra == "all"
|
|
53
|
+
Dynamic: license-file
|
|
54
|
+
|
|
55
|
+
# Everyome
|
|
56
|
+
|
|
57
|
+
*Every -ome, for everyone.*
|
|
58
|
+
|
|
59
|
+
Created by **Helen R Horkan PhD** (Stowers Institute). If you use Everyome, adapt its
|
|
60
|
+
code, or reuse its text or figures, please cite it (see [`CITATION.cff`](https://github.com/Everyome/everyome/blob/main/CITATION.cff)).
|
|
61
|
+
|
|
62
|
+
Everyome is a free, open-source platform for omics analysis. It gives biologists a
|
|
63
|
+
simple point-and-click interface while keeping every setting visible and editable.
|
|
64
|
+
It runs on your own computer or on your own Slurm cluster account over SSH, so
|
|
65
|
+
your data stays where it is.
|
|
66
|
+
|
|
67
|
+
Planned suites: DNA, RNA, single cell, spatial, protein, molecular biology and
|
|
68
|
+
phylogenetics. Every module will come with a manual, a playground, guides to
|
|
69
|
+
reading its output, and a lab-book protocol and methods section for every run.
|
|
70
|
+
|
|
71
|
+
Everyome grows out of SPLiTscape (SPLiT-seq reads to annotated cell atlases),
|
|
72
|
+
which becomes its first single-cell module and keeps its own citation.
|
|
73
|
+
|
|
74
|
+
## Status
|
|
75
|
+
|
|
76
|
+
The core is in place (phase 1 of [`docs/PLAN.md`](https://github.com/Everyome/everyome/blob/main/docs/PLAN.md)): connect to a
|
|
77
|
+
cluster or the built-in demo cluster, create projects, choose an analysis, fill
|
|
78
|
+
in its settings, check the exact job scripts, submit them, follow the jobs, and
|
|
79
|
+
explore the results in a live session. Every run then gets a lab-book
|
|
80
|
+
protocol, a draft methods section to edit, its references, and a bundle that
|
|
81
|
+
repeats it exactly.
|
|
82
|
+
|
|
83
|
+
Modules so far:
|
|
84
|
+
- **SPLiT-seq (SPLiTscape)**, single cell: SPLiT-seq sublibraries from raw reads
|
|
85
|
+
to annotated cell types, on their own (for example, to build a first atlas) or
|
|
86
|
+
merged with an existing atlas or dataset. Includes a playground.
|
|
87
|
+
- **Bulk RNA-seq differential expression**, RNA: nf-core/rnaseq turns reads into
|
|
88
|
+
gene counts on the cluster, then DESeq2 compares conditions in a live session.
|
|
89
|
+
- **Sequence summary**, getting started: a small worked example of how every
|
|
90
|
+
module runs.
|
|
91
|
+
|
|
92
|
+
## Install
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install "everyome==0.1.0a1" # the app and the tutorial
|
|
96
|
+
pip install "everyome[all]==0.1.0a1" # plus SPLiT-seq and bulk RNA-seq (Scanpy, PyDESeq2, ...)
|
|
97
|
+
everyome # opens http://127.0.0.1:8777
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Naming the version installs this early release of Everyome while everything it
|
|
101
|
+
needs comes from normal, stable releases. (Avoid `pip install --pre`: it would
|
|
102
|
+
also pull in unfinished versions of other packages.) Everyome needs Python 3.10
|
|
103
|
+
or newer and runs on macOS and Linux. Choose **Demo
|
|
104
|
+
cluster** to try everything on your own computer, with example data and a
|
|
105
|
+
pretend job scheduler; demo data lives in `~/.everyome/demo_cluster` (delete it
|
|
106
|
+
to start fresh). To use your own cluster, Everyome also needs to be installed in
|
|
107
|
+
a Python environment there (ask IT for a shared one), and the readiness checks
|
|
108
|
+
tell you what is missing.
|
|
109
|
+
|
|
110
|
+
## Develop
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
git clone https://github.com/Everyome/everyome && cd everyome
|
|
114
|
+
pip install -e ".[test,all]"
|
|
115
|
+
pytest
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Licence
|
|
119
|
+
|
|
120
|
+
MIT (see `LICENSE`). Fonts, UMAP-JS and the nf-core/rnaseq schemas that ship
|
|
121
|
+
with Everyome keep their own licences; see `THIRD_PARTY_NOTICES.md`.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Everyome
|
|
2
|
+
|
|
3
|
+
*Every -ome, for everyone.*
|
|
4
|
+
|
|
5
|
+
Created by **Helen R Horkan PhD** (Stowers Institute). If you use Everyome, adapt its
|
|
6
|
+
code, or reuse its text or figures, please cite it (see [`CITATION.cff`](https://github.com/Everyome/everyome/blob/main/CITATION.cff)).
|
|
7
|
+
|
|
8
|
+
Everyome is a free, open-source platform for omics analysis. It gives biologists a
|
|
9
|
+
simple point-and-click interface while keeping every setting visible and editable.
|
|
10
|
+
It runs on your own computer or on your own Slurm cluster account over SSH, so
|
|
11
|
+
your data stays where it is.
|
|
12
|
+
|
|
13
|
+
Planned suites: DNA, RNA, single cell, spatial, protein, molecular biology and
|
|
14
|
+
phylogenetics. Every module will come with a manual, a playground, guides to
|
|
15
|
+
reading its output, and a lab-book protocol and methods section for every run.
|
|
16
|
+
|
|
17
|
+
Everyome grows out of SPLiTscape (SPLiT-seq reads to annotated cell atlases),
|
|
18
|
+
which becomes its first single-cell module and keeps its own citation.
|
|
19
|
+
|
|
20
|
+
## Status
|
|
21
|
+
|
|
22
|
+
The core is in place (phase 1 of [`docs/PLAN.md`](https://github.com/Everyome/everyome/blob/main/docs/PLAN.md)): connect to a
|
|
23
|
+
cluster or the built-in demo cluster, create projects, choose an analysis, fill
|
|
24
|
+
in its settings, check the exact job scripts, submit them, follow the jobs, and
|
|
25
|
+
explore the results in a live session. Every run then gets a lab-book
|
|
26
|
+
protocol, a draft methods section to edit, its references, and a bundle that
|
|
27
|
+
repeats it exactly.
|
|
28
|
+
|
|
29
|
+
Modules so far:
|
|
30
|
+
- **SPLiT-seq (SPLiTscape)**, single cell: SPLiT-seq sublibraries from raw reads
|
|
31
|
+
to annotated cell types, on their own (for example, to build a first atlas) or
|
|
32
|
+
merged with an existing atlas or dataset. Includes a playground.
|
|
33
|
+
- **Bulk RNA-seq differential expression**, RNA: nf-core/rnaseq turns reads into
|
|
34
|
+
gene counts on the cluster, then DESeq2 compares conditions in a live session.
|
|
35
|
+
- **Sequence summary**, getting started: a small worked example of how every
|
|
36
|
+
module runs.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install "everyome==0.1.0a1" # the app and the tutorial
|
|
42
|
+
pip install "everyome[all]==0.1.0a1" # plus SPLiT-seq and bulk RNA-seq (Scanpy, PyDESeq2, ...)
|
|
43
|
+
everyome # opens http://127.0.0.1:8777
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Naming the version installs this early release of Everyome while everything it
|
|
47
|
+
needs comes from normal, stable releases. (Avoid `pip install --pre`: it would
|
|
48
|
+
also pull in unfinished versions of other packages.) Everyome needs Python 3.10
|
|
49
|
+
or newer and runs on macOS and Linux. Choose **Demo
|
|
50
|
+
cluster** to try everything on your own computer, with example data and a
|
|
51
|
+
pretend job scheduler; demo data lives in `~/.everyome/demo_cluster` (delete it
|
|
52
|
+
to start fresh). To use your own cluster, Everyome also needs to be installed in
|
|
53
|
+
a Python environment there (ask IT for a shared one), and the readiness checks
|
|
54
|
+
tell you what is missing.
|
|
55
|
+
|
|
56
|
+
## Develop
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/Everyome/everyome && cd everyome
|
|
60
|
+
pip install -e ".[test,all]"
|
|
61
|
+
pytest
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Licence
|
|
65
|
+
|
|
66
|
+
MIT (see `LICENSE`). Fonts, UMAP-JS and the nf-core/rnaseq schemas that ship
|
|
67
|
+
with Everyome keep their own licences; see `THIRD_PARTY_NOTICES.md`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Third-party material in Everyome
|
|
2
|
+
|
|
3
|
+
Everyome itself is under the MIT licence (`LICENSE`). It ships the following
|
|
4
|
+
material from others, each under its own licence, with the licence text next to it.
|
|
5
|
+
|
|
6
|
+
| What | Where | Licence |
|
|
7
|
+
|---|---|---|
|
|
8
|
+
| Fonts (Fontsource builds of open-source typefaces) | `everyome/static/fonts/` | SIL Open Font License 1.1; one `*-LICENSE` file per family |
|
|
9
|
+
| UMAP-JS (used by the SPLiT-seq playground) | `everyome/modules/singlecell/splitseq/docs/playground/umap-js.min.js` | Apache License 2.0; `UMAP-JS-LICENSE` in the same folder |
|
|
10
|
+
| nf-core/rnaseq 3.27.0 parameter and samplesheet schemas | `everyome/modules/rna/bulk_de/pipeline/` | MIT; `LICENSE-nf-core-rnaseq` in the same folder |
|
|
11
|
+
|
|
12
|
+
Everyome runs, but does not include, other tools (for example nf-core/rnaseq,
|
|
13
|
+
Nextflow, STAR, Salmon, cutadapt, Scanpy, Harmony, PyDESeq2). Each analysis
|
|
14
|
+
lists the tools it uses and how to cite them in its manual and in each run's
|
|
15
|
+
write-up.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Start Everyome: `everyome` (or `python -m everyome`) opens the app in your browser."""
|
|
2
|
+
import argparse
|
|
3
|
+
import os
|
|
4
|
+
import threading
|
|
5
|
+
import webbrowser
|
|
6
|
+
|
|
7
|
+
import uvicorn
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main():
|
|
11
|
+
ap = argparse.ArgumentParser(description="Everyome: every -ome, for everyone")
|
|
12
|
+
ap.add_argument("--port", type=int, default=8777)
|
|
13
|
+
ap.add_argument("--no-browser", action="store_true", help="do not open a browser window")
|
|
14
|
+
a = ap.parse_args()
|
|
15
|
+
try:
|
|
16
|
+
import setproctitle
|
|
17
|
+
# Intent: Stowers policy names every process Claude_<user>_<tool>_<stage>.
|
|
18
|
+
setproctitle.setproctitle(f"Claude_{os.environ.get('USER', 'user')}_everyome_app")
|
|
19
|
+
except ImportError:
|
|
20
|
+
pass
|
|
21
|
+
url = f"http://127.0.0.1:{a.port}"
|
|
22
|
+
if not a.no_browser:
|
|
23
|
+
threading.Timer(1.2, lambda: webbrowser.open(url)).start()
|
|
24
|
+
print(f"Everyome is running at {url} (press Ctrl+C to quit)")
|
|
25
|
+
# Intent: listen on localhost only; the app is for this computer's user.
|
|
26
|
+
uvicorn.run("everyome.core.server:app", host="127.0.0.1", port=a.port, log_level="warning")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core: backends, scheduler, projects, runs and the module loader (see docs/PLAN.md, section 3)."""
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""How the app talks to the computer that does the work (carried over from SPLiTscape).
|
|
2
|
+
|
|
3
|
+
Two backends with one interface:
|
|
4
|
+
* SSHBackend — a real cluster. Uses the system `ssh` client, so the user's
|
|
5
|
+
key, ssh-agent, ~/.ssh/config and jump hosts all apply. The
|
|
6
|
+
app never reads the private key. BatchMode means it never
|
|
7
|
+
prompts for a password: key-based login only.
|
|
8
|
+
* LocalBackend — this computer, inside a folder. With fake Slurm on PATH it is
|
|
9
|
+
the demo cluster; without it, it runs local modules.
|
|
10
|
+
|
|
11
|
+
Both expose: run, read_bytes, write_bytes, listdir, exists, tunnel, close.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import shlex
|
|
17
|
+
import socket
|
|
18
|
+
import subprocess
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class Entry:
|
|
25
|
+
name: str
|
|
26
|
+
is_dir: bool
|
|
27
|
+
size: int
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def free_port() -> int:
|
|
31
|
+
with socket.socket() as s:
|
|
32
|
+
s.bind(("127.0.0.1", 0))
|
|
33
|
+
return s.getsockname()[1]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Backend:
|
|
37
|
+
label = "cluster"
|
|
38
|
+
user = "unknown"
|
|
39
|
+
|
|
40
|
+
def run(self, cmd: str, timeout: float = 60, stdin: bytes | None = None) -> tuple[int, str, str]:
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
|
|
43
|
+
def read_bytes(self, path: str) -> bytes:
|
|
44
|
+
rc, out, err = self.run_bytes(f"cat {shlex.quote(path)}")
|
|
45
|
+
if rc:
|
|
46
|
+
raise FileNotFoundError(f"{path}: {err.strip()}")
|
|
47
|
+
return out
|
|
48
|
+
|
|
49
|
+
def read_text(self, path: str) -> str:
|
|
50
|
+
return self.read_bytes(path).decode()
|
|
51
|
+
|
|
52
|
+
def write_bytes(self, path: str, data: bytes) -> None:
|
|
53
|
+
q = shlex.quote(path)
|
|
54
|
+
rc, _, err = self.run(f"mkdir -p $(dirname {q}) && cat > {q}", stdin=data)
|
|
55
|
+
if rc:
|
|
56
|
+
raise OSError(f"could not write {path}: {err.strip()}")
|
|
57
|
+
|
|
58
|
+
def write_text(self, path: str, text: str) -> None:
|
|
59
|
+
self.write_bytes(path, text.encode())
|
|
60
|
+
|
|
61
|
+
def exists(self, path: str) -> bool:
|
|
62
|
+
return self.run(f"test -e {shlex.quote(path)}")[0] == 0
|
|
63
|
+
|
|
64
|
+
def listdir(self, path: str) -> list[Entry]:
|
|
65
|
+
# Intent: portable listing (type, size, name), one entry per line.
|
|
66
|
+
cmd = (f"cd {shlex.quote(path)} && for f in * .[!.]*; do [ -e \"$f\" ] || continue; "
|
|
67
|
+
"if [ -d \"$f\" ]; then t=d; s=0; else t=f; s=$(wc -c < \"$f\" | tr -d ' '); fi; "
|
|
68
|
+
"printf '%s\\t%s\\t%s\\n' \"$t\" \"$s\" \"$f\"; done")
|
|
69
|
+
rc, out, err = self.run(cmd)
|
|
70
|
+
if rc:
|
|
71
|
+
raise FileNotFoundError(f"{path}: {err.strip() or 'not a folder'}")
|
|
72
|
+
rows = [line.split("\t", 2) for line in out.splitlines() if line.count("\t") >= 2]
|
|
73
|
+
return sorted((Entry(n, t == "d", int(s)) for t, s, n in rows), key=lambda e: (not e.is_dir, e.name.lower()))
|
|
74
|
+
|
|
75
|
+
def run_bytes(self, cmd: str, timeout: float = 120) -> tuple[int, bytes, str]:
|
|
76
|
+
raise NotImplementedError
|
|
77
|
+
|
|
78
|
+
def tunnel(self, node: str, remote_port: int) -> int:
|
|
79
|
+
"""Forward a local port to node:remote_port; returns the local port."""
|
|
80
|
+
raise NotImplementedError
|
|
81
|
+
|
|
82
|
+
def close(self) -> None:
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class LocalBackend(Backend):
|
|
87
|
+
"""This computer: a working folder, optionally with fake Slurm commands (the demo cluster)."""
|
|
88
|
+
|
|
89
|
+
def __init__(self, root: Path, fake_slurm_bin: Path | None = None, label: str = "this computer"):
|
|
90
|
+
self.root = root
|
|
91
|
+
self.label = label
|
|
92
|
+
self.env = dict(os.environ)
|
|
93
|
+
if fake_slurm_bin:
|
|
94
|
+
self.env["PATH"] = f"{fake_slurm_bin}{os.pathsep}{self.env.get('PATH', '')}"
|
|
95
|
+
self.env["FAKE_SLURM_HOME"] = str(root / ".slurm")
|
|
96
|
+
# Intent: jobs import this same copy of Everyome, as they would from a cluster install.
|
|
97
|
+
self.env["PYTHONPATH"] = os.pathsep.join(filter(None, [str(Path(__file__).resolve().parents[2]), self.env.get("PYTHONPATH")]))
|
|
98
|
+
self.user = os.environ.get("USER", "user")
|
|
99
|
+
self.host = "localhost"
|
|
100
|
+
|
|
101
|
+
def run(self, cmd, timeout=60, stdin=None):
|
|
102
|
+
p = subprocess.run(["bash", "-c", cmd], cwd=self.root, env=self.env, input=stdin,
|
|
103
|
+
capture_output=True, timeout=timeout)
|
|
104
|
+
return p.returncode, p.stdout.decode(errors="replace"), p.stderr.decode(errors="replace")
|
|
105
|
+
|
|
106
|
+
def run_bytes(self, cmd, timeout=120):
|
|
107
|
+
p = subprocess.run(["bash", "-c", cmd], cwd=self.root, env=self.env, capture_output=True, timeout=timeout)
|
|
108
|
+
return p.returncode, p.stdout, p.stderr.decode(errors="replace")
|
|
109
|
+
|
|
110
|
+
def tunnel(self, node, remote_port):
|
|
111
|
+
return remote_port # same machine: nothing to forward
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class SSHBackend(Backend):
|
|
115
|
+
"""Real cluster over OpenSSH with connection sharing (one login, many commands)."""
|
|
116
|
+
|
|
117
|
+
def __init__(self, host: str, user: str, port: int = 22, ssh_options: list[str] | None = None):
|
|
118
|
+
self.host, self.user, self.port = host, user, port
|
|
119
|
+
self.label = f"{user}@{host}"
|
|
120
|
+
ctl = Path.home() / ".ssh" / "everyome-%r@%h-%p"
|
|
121
|
+
(Path.home() / ".ssh").mkdir(mode=0o700, exist_ok=True)
|
|
122
|
+
# Intent: share one login across commands (not supported by Windows' OpenSSH).
|
|
123
|
+
share = [] if os.name == "nt" else ["-o", "ControlMaster=auto", "-o", f"ControlPath={ctl}", "-o", "ControlPersist=15m"]
|
|
124
|
+
self.base = ["ssh", "-p", str(port), "-o", "BatchMode=yes", "-o", "ConnectTimeout=15", *share,
|
|
125
|
+
"-o", "ServerAliveInterval=30", *(ssh_options or []), f"{user}@{host}"]
|
|
126
|
+
self.tunnels: list[subprocess.Popen] = []
|
|
127
|
+
|
|
128
|
+
def _ssh(self, cmd, stdin=None, timeout=60):
|
|
129
|
+
# Intent: run under a login shell so the user's cluster PATH (Slurm, modules) is set.
|
|
130
|
+
return subprocess.run([*self.base, f"bash -lc {shlex.quote(cmd)}"], input=stdin, capture_output=True, timeout=timeout)
|
|
131
|
+
|
|
132
|
+
def run(self, cmd, timeout=60, stdin=None):
|
|
133
|
+
p = self._ssh(cmd, stdin, timeout)
|
|
134
|
+
return p.returncode, p.stdout.decode(errors="replace"), p.stderr.decode(errors="replace")
|
|
135
|
+
|
|
136
|
+
def run_bytes(self, cmd, timeout=120):
|
|
137
|
+
p = self._ssh(cmd, None, timeout)
|
|
138
|
+
return p.returncode, p.stdout, p.stderr.decode(errors="replace")
|
|
139
|
+
|
|
140
|
+
def tunnel(self, node, remote_port):
|
|
141
|
+
lport = free_port()
|
|
142
|
+
args = [a for a in self.base if a != f"{self.user}@{self.host}"]
|
|
143
|
+
proc = subprocess.Popen([*args, "-N", "-o", "ExitOnForwardFailure=yes",
|
|
144
|
+
"-L", f"127.0.0.1:{lport}:{node}:{remote_port}", f"{self.user}@{self.host}"],
|
|
145
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
|
|
146
|
+
self.tunnels.append(proc)
|
|
147
|
+
return lport
|
|
148
|
+
|
|
149
|
+
def close(self):
|
|
150
|
+
for t in self.tunnels:
|
|
151
|
+
t.terminate()
|
|
152
|
+
subprocess.run([*self.base[:-1], "-O", "exit", f"{self.user}@{self.host}"], capture_output=True)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def describe_ssh_error(err: str) -> str:
|
|
156
|
+
"""Turn common ssh failures into plain-language advice."""
|
|
157
|
+
e = err.lower()
|
|
158
|
+
if "permission denied" in e:
|
|
159
|
+
return "The cluster refused your key. Check that your SSH key is added to the cluster and loaded (ssh-add)."
|
|
160
|
+
if "could not resolve" in e or "name or service not known" in e:
|
|
161
|
+
return "That cluster address could not be found. Check the host name, and that you are on the institute network or VPN."
|
|
162
|
+
if "timed out" in e or "no route" in e:
|
|
163
|
+
return "The cluster did not answer. Check you are on the institute network or VPN."
|
|
164
|
+
if "host key verification failed" in e:
|
|
165
|
+
return "Your computer has not seen this cluster before. Log in once from a terminal to accept its host key, or ask IT."
|
|
166
|
+
return err.strip() or "Connection failed."
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""The demo cluster: a folder on this computer plus a pretend Slurm.
|
|
2
|
+
|
|
3
|
+
<root>/
|
|
4
|
+
projects/ where demo projects are saved
|
|
5
|
+
data/<module id>/ each module's small demo dataset
|
|
6
|
+
.bin/ sbatch, squeue, sacct, scancel (fake_slurm.py)
|
|
7
|
+
.slurm/ the pretend scheduler's job records
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import importlib
|
|
12
|
+
import shlex
|
|
13
|
+
import shutil
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
HERE = Path(__file__).resolve().parent
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def setup(root: Path, modules: dict) -> Path:
|
|
21
|
+
"""Create or refresh the demo cluster; returns the folder holding the fake Slurm commands."""
|
|
22
|
+
(root / "projects").mkdir(parents=True, exist_ok=True)
|
|
23
|
+
for m in modules.values():
|
|
24
|
+
if m.demo.get("data"):
|
|
25
|
+
# Intent: refresh demo data from the installed modules, never touching users' demo projects.
|
|
26
|
+
shutil.copytree(m.dir / m.demo["data"], root / "data" / m.id, dirs_exist_ok=True)
|
|
27
|
+
if m.demo.get("build") and not (root / "data" / m.id / ".demo_ready").exists():
|
|
28
|
+
# Intent: modules whose demo data is generated (too large to ship) build it once, here.
|
|
29
|
+
mod, _, fn = m.demo["build"].partition(":")
|
|
30
|
+
getattr(importlib.import_module(mod), fn)(root / "data" / m.id)
|
|
31
|
+
(root / "data" / m.id / ".demo_ready").write_text("1")
|
|
32
|
+
bin_dir = root / ".bin"
|
|
33
|
+
bin_dir.mkdir(exist_ok=True)
|
|
34
|
+
for cmd in ("sbatch", "squeue", "sacct", "scancel"):
|
|
35
|
+
f = bin_dir / cmd
|
|
36
|
+
f.write_text(f"#!/bin/bash\nexec {shlex.quote(sys.executable)} {shlex.quote(str(HERE / 'fake_slurm.py'))} {cmd} \"$@\"\n")
|
|
37
|
+
f.chmod(0o755)
|
|
38
|
+
return bin_dir
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""A tiny stand-in for Slurm, used by the demo cluster.
|
|
2
|
+
|
|
3
|
+
Implements the subset Everyome uses (carried over from SPLiTscape):
|
|
4
|
+
sbatch [--parsable] [--dependency=afterok:ID[:ID]] [--job-name=..] [--output=..] script
|
|
5
|
+
squeue -h -j IDS -o "%i %T %N"
|
|
6
|
+
sacct -n -P -j IDS -o JobID,State,Elapsed
|
|
7
|
+
scancel ID [ID ...]
|
|
8
|
+
|
|
9
|
+
Jobs run as background processes; state lives in $FAKE_SLURM_HOME.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import re
|
|
16
|
+
import socket
|
|
17
|
+
import subprocess
|
|
18
|
+
import sys
|
|
19
|
+
import time
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
HOME = Path(os.environ.get("FAKE_SLURM_HOME", Path.home() / ".fake_slurm"))
|
|
23
|
+
JOBS = HOME / "jobs"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _load(jid):
|
|
27
|
+
return json.loads((JOBS / f"{jid}.json").read_text())
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _save(job):
|
|
31
|
+
tmp = JOBS / f"{job['id']}.json.tmp"
|
|
32
|
+
tmp.write_text(json.dumps(job))
|
|
33
|
+
tmp.replace(JOBS / f"{job['id']}.json")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _directives(script: str) -> dict:
|
|
37
|
+
out = {}
|
|
38
|
+
for line in Path(script).read_text().splitlines():
|
|
39
|
+
m = re.match(r"#SBATCH\s+--([\w-]+)(?:[= ](.+))?", line.strip())
|
|
40
|
+
if m:
|
|
41
|
+
out[m.group(1)] = (m.group(2) or "").strip()
|
|
42
|
+
return out
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def sbatch(args):
|
|
46
|
+
JOBS.mkdir(parents=True, exist_ok=True)
|
|
47
|
+
opts, script = {}, None
|
|
48
|
+
for a in args:
|
|
49
|
+
if a.startswith("--"):
|
|
50
|
+
k, _, v = a[2:].partition("=")
|
|
51
|
+
opts[k] = v
|
|
52
|
+
else:
|
|
53
|
+
script = a
|
|
54
|
+
if not script:
|
|
55
|
+
sys.exit("sbatch: no script given")
|
|
56
|
+
opts = {**_directives(script), **opts}
|
|
57
|
+
counter = HOME / "counter"
|
|
58
|
+
jid = int(counter.read_text()) + 1 if counter.exists() else 1001
|
|
59
|
+
counter.write_text(str(jid))
|
|
60
|
+
deps = []
|
|
61
|
+
if opts.get("dependency", "").startswith("afterok:"):
|
|
62
|
+
deps = [int(x) for x in opts["dependency"][8:].split(":") if x]
|
|
63
|
+
out = opts.get("output", str(Path.cwd() / f"slurm-{jid}.out")).replace("%j", str(jid))
|
|
64
|
+
job = {"id": jid, "name": opts.get("job-name", Path(script).name), "script": str(Path(script).resolve()),
|
|
65
|
+
"cwd": str(Path.cwd()), "output": out, "deps": deps, "state": "PENDING", "start": None, "end": None,
|
|
66
|
+
"node": socket.gethostname(), "pid": None}
|
|
67
|
+
_save(job)
|
|
68
|
+
# Intent: detach a runner that waits for dependencies, then executes the script.
|
|
69
|
+
subprocess.Popen([sys.executable, __file__, "_run", str(jid)], start_new_session=True,
|
|
70
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=os.environ.copy())
|
|
71
|
+
print(jid if "parsable" in opts else f"Submitted batch job {jid}")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _run(jid):
|
|
75
|
+
job = _load(jid)
|
|
76
|
+
while True:
|
|
77
|
+
states = [_load(d)["state"] for d in job["deps"]]
|
|
78
|
+
if any(s in ("FAILED", "CANCELLED", "TIMEOUT") for s in states):
|
|
79
|
+
job = _load(jid); job.update(state="CANCELLED", reason="DependencyNeverSatisfied", end=time.time()); _save(job); return
|
|
80
|
+
if all(s == "COMPLETED" for s in states):
|
|
81
|
+
break
|
|
82
|
+
if _load(jid)["state"] == "CANCELLED":
|
|
83
|
+
return
|
|
84
|
+
time.sleep(0.5)
|
|
85
|
+
job = _load(jid)
|
|
86
|
+
if job["state"] == "CANCELLED":
|
|
87
|
+
return
|
|
88
|
+
Path(job["output"]).parent.mkdir(parents=True, exist_ok=True)
|
|
89
|
+
with open(job["output"], "w") as log:
|
|
90
|
+
env = dict(os.environ, SLURM_JOB_ID=str(jid), SLURMD_NODENAME=job["node"])
|
|
91
|
+
p = subprocess.Popen(["bash", job["script"]], cwd=job["cwd"], stdout=log, stderr=subprocess.STDOUT, env=env, start_new_session=True)
|
|
92
|
+
job.update(state="RUNNING", start=time.time(), pid=p.pid); _save(job)
|
|
93
|
+
rc = p.wait()
|
|
94
|
+
job = _load(jid)
|
|
95
|
+
if job["state"] != "CANCELLED":
|
|
96
|
+
job.update(state="COMPLETED" if rc == 0 else "FAILED", end=time.time(), exit=rc); _save(job)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _ids(args):
|
|
100
|
+
for i, a in enumerate(args):
|
|
101
|
+
if a == "-j" and i + 1 < len(args):
|
|
102
|
+
return [int(x) for x in args[i + 1].split(",") if x]
|
|
103
|
+
if a.startswith("--jobs="):
|
|
104
|
+
return [int(x) for x in a[7:].split(",") if x]
|
|
105
|
+
return sorted(int(p.stem) for p in JOBS.glob("*.json")) if JOBS.exists() else []
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _elapsed(job):
|
|
109
|
+
if not job["start"]:
|
|
110
|
+
return "00:00:00"
|
|
111
|
+
s = int((job["end"] or time.time()) - job["start"])
|
|
112
|
+
return f"{s // 3600:02d}:{s % 3600 // 60:02d}:{s % 60:02d}"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def squeue(args):
|
|
116
|
+
for jid in _ids(args):
|
|
117
|
+
try:
|
|
118
|
+
j = _load(jid)
|
|
119
|
+
except FileNotFoundError:
|
|
120
|
+
continue
|
|
121
|
+
if j["state"] in ("PENDING", "RUNNING"):
|
|
122
|
+
print(f"{jid} {j['state']} {j['node'] if j['state'] == 'RUNNING' else '(None)'}")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def sacct(args):
|
|
126
|
+
for jid in _ids(args):
|
|
127
|
+
try:
|
|
128
|
+
j = _load(jid)
|
|
129
|
+
except FileNotFoundError:
|
|
130
|
+
continue
|
|
131
|
+
print(f"{jid}|{j['state']}|{_elapsed(j)}")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def scancel(args):
|
|
135
|
+
for a in args:
|
|
136
|
+
if not a.isdigit():
|
|
137
|
+
continue
|
|
138
|
+
j = _load(int(a))
|
|
139
|
+
if j["state"] in ("PENDING", "RUNNING"):
|
|
140
|
+
if j.get("pid"):
|
|
141
|
+
try:
|
|
142
|
+
os.killpg(j["pid"], 15)
|
|
143
|
+
except ProcessLookupError:
|
|
144
|
+
pass
|
|
145
|
+
j.update(state="CANCELLED", end=time.time()); _save(j)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
cmd, rest = sys.argv[1], sys.argv[2:]
|
|
150
|
+
{"sbatch": sbatch, "squeue": squeue, "sacct": sacct, "scancel": scancel,
|
|
151
|
+
"_run": lambda a: _run(int(a[0]))}[cmd](rest)
|