Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new command-line option --citation for installed version #228

Merged
merged 96 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
5923de6
add `--citation` flag to print out CITATION.cff
alexlancaster Nov 10, 2024
2b50759
generate different citation formats at build-time
alexlancaster Nov 10, 2024
cfcf4b6
simplify CitationAction
alexlancaster Nov 10, 2024
fb16508
document `--citation` option
alexlancaster Nov 10, 2024
365876e
Use my custom cffconvert
alexlancaster Nov 10, 2024
e7d2ecf
try cffconvert version
alexlancaster Nov 10, 2024
d46f63f
try adding "docopt>=0.6.2"
alexlancaster Nov 11, 2024
dde45ae
allow `docopt` to be installed from source
alexlancaster Nov 11, 2024
caaffc7
workaround to force `docopt` installation
alexlancaster Nov 11, 2024
43c3183
try config-settings
alexlancaster Nov 11, 2024
9edc53f
fix settings
alexlancaster Nov 11, 2024
f14b8ac
add argument in build-frontend
alexlancaster Nov 11, 2024
c596c8c
config-settings
alexlancaster Nov 11, 2024
7470a3a
add requirements for pip for cffconvert
alexlancaster Nov 11, 2024
6a93385
typo
alexlancaster Nov 11, 2024
fdabedf
add `docopt`
alexlancaster Nov 11, 2024
175be43
another test
alexlancaster Nov 11, 2024
22ef232
try again
alexlancaster Nov 11, 2024
822f555
just keep --no-binary docopt
alexlancaster Nov 11, 2024
8bdb63e
Just set PIP_ONLY_BINARY during unit testing
alexlancaster Nov 11, 2024
a079ac9
Need to modify the test command in the action
alexlancaster Nov 11, 2024
2790f93
Use before-test to set env variable
alexlancaster Nov 11, 2024
922f4fd
add psutil with no binary to test the envvar works
alexlancaster Nov 11, 2024
a6732fd
use bibtexparser, not psutil (which does have a binary package)
alexlancaster Nov 11, 2024
e3aabc0
tidy before-test command
alexlancaster Nov 11, 2024
97be63b
try and customize via the `build-frontend`
alexlancaster Nov 12, 2024
9a5be3a
use production version of cffconvert
alexlancaster Nov 12, 2024
b55fb6c
override ONLY_BINARY envar
alexlancaster Nov 12, 2024
8cc1b6c
add test `docopt`
alexlancaster Nov 12, 2024
3d43c66
tidy pyproject.toml
alexlancaster Nov 12, 2024
745eb32
move `import cffconvert` into class
alexlancaster Nov 12, 2024
a756122
allow `--citation` to work for editable installs too
alexlancaster Nov 12, 2024
a4a4dbf
full URL to the guide
alexlancaster Nov 12, 2024
3724c03
fmting
alexlancaster Nov 12, 2024
f4bb1a8
add more rationale for citing the specific version
alexlancaster Nov 12, 2024
c38162f
use my fork of cffconvert
alexlancaster Nov 13, 2024
bca4b71
update citations as an action rather in the package
alexlancaster Nov 13, 2024
942d773
minor reordering
alexlancaster Nov 13, 2024
3887419
fix syntax
alexlancaster Nov 13, 2024
f20f0db
don't re-run build workflow after changes to citation updates
alexlancaster Nov 13, 2024
794bb97
another reorder
alexlancaster Nov 13, 2024
ce36a41
syntax error
alexlancaster Nov 13, 2024
f0308d0
re-run upon changes to workflow files
alexlancaster Nov 13, 2024
90a91d1
reference the workflow dynamically
alexlancaster Nov 13, 2024
3052af0
wrong name of yml
alexlancaster Nov 13, 2024
3eb1fad
syntax fix
alexlancaster Nov 13, 2024
1e3d80c
don't expand the repo name, not necessary
alexlancaster Nov 13, 2024
09315fb
use github.ref
alexlancaster Nov 13, 2024
4fd9afb
have to hardcode branch :(
alexlancaster Nov 13, 2024
a55d38c
fix reusable workflow syntax
alexlancaster Nov 13, 2024
0a8b92e
more syntax fixes
alexlancaster Nov 13, 2024
b85b1e1
local workflow doesn't need version
alexlancaster Nov 13, 2024
071391d
add needs
alexlancaster Nov 13, 2024
54ec929
do citation updates
alexlancaster Nov 13, 2024
ea4a640
fix more syntax
alexlancaster Nov 13, 2024
7683a19
supply type
alexlancaster Nov 13, 2024
103df2c
missing 'runs-on'
alexlancaster Nov 13, 2024
5a08051
make into an action
alexlancaster Nov 13, 2024
8dc9b99
convert to action
alexlancaster Nov 13, 2024
bb6fe38
rename to action.yml
alexlancaster Nov 13, 2024
2aeb55c
use a default shell
alexlancaster Nov 13, 2024
9b35134
depend on action file
alexlancaster Nov 13, 2024
eebd3e6
need shell for each step
alexlancaster Nov 13, 2024
be4b9b6
change deps
alexlancaster Nov 13, 2024
a75f933
use set-output
alexlancaster Nov 13, 2024
4b417fd
Auto-update citation files based on CITATION.cff
alexlancaster Nov 13, 2024
41632f6
wrong prefix
alexlancaster Nov 13, 2024
7cf6026
use `CITATION` not `citation` as file prefix
alexlancaster Nov 13, 2024
bd27f92
Auto-update citation files based on CITATION.cff
alexlancaster Nov 13, 2024
8725331
read from files in repo, statically generated by action
alexlancaster Nov 13, 2024
2e3a83c
note to end-user to not modify files directly
alexlancaster Nov 13, 2024
77c3cad
tweak
alexlancaster Nov 13, 2024
f0788f4
Auto-update citation files based on CITATION.cff
alexlancaster Nov 13, 2024
4f4c459
return to generating different formats on the fly
alexlancaster Nov 13, 2024
072cb35
missing file
alexlancaster Nov 13, 2024
ff2486d
Remove cffconvert from build-system requires in pyproject.toml
alexlancaster Nov 13, 2024
6084a3a
use a Python script more cross-platform
alexlancaster Nov 13, 2024
9787069
generate citiation formats
alexlancaster Nov 14, 2024
fe6cf41
debugging
alexlancaster Nov 14, 2024
696c990
install recent Python to handle cffconvert
alexlancaster Nov 14, 2024
1e51cc8
install stable 3.12
alexlancaster Nov 14, 2024
5eb5559
remove unused workflows and actions
alexlancaster Nov 14, 2024
ecec313
fallback to top-level CITATION.cff
alexlancaster Nov 14, 2024
35b513d
add all currently supported conversions for completeness
alexlancaster Nov 14, 2024
9e88364
note that `--citation` option has only existed since v1.1.2
alexlancaster Nov 14, 2024
98ad2ff
Override the setuptools scm version because we modified project.toml
alexlancaster Nov 14, 2024
11f2243
Need to save version before modification of TOML file
alexlancaster Nov 16, 2024
a95757b
Don't override existing CIBW_ENVIRONMENT
alexlancaster Nov 16, 2024
62460f4
Use bash in a step to avoid Windows issue
alexlancaster Nov 16, 2024
479b0af
Debugging
alexlancaster Nov 16, 2024
6c95924
Need version scheme
alexlancaster Nov 16, 2024
2817359
Typo
alexlancaster Nov 16, 2024
f8dd4e0
Need to pass through some envvar to Linux container
alexlancaster Nov 16, 2024
005741c
Install recent Python earlier in build process
alexlancaster Nov 16, 2024
9385fbe
mostly whitespace fixes
alexlancaster Nov 18, 2024
6328fb4
date fix
alexlancaster Nov 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions .github/workflows/build_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ on:
- '.github/workflows/documentation.yaml'
- '.github/workflows/buildjet_arm64.yml'
- '.github/workflows/release-drafter.yml'
- '.github/workflows/codeql.yml'
- '.github/workflows/codeql.yml'
- '.gitattributes'
push:
paths-ignore:
Expand All @@ -34,7 +34,7 @@ on:
- '.github/workflows/documentation.yaml'
- '.github/workflows/buildjet_arm64.yml'
- '.github/workflows/release-drafter.yml'
- '.github/workflows/codeql.yml'
- '.github/workflows/codeql.yml'
- '.gitattributes'
release:
types:
Expand Down Expand Up @@ -178,12 +178,45 @@ jobs:
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v3
with:
platforms: all
platforms: all
- name: Install a recent stable Python to handle Python deps
uses: actions/setup-python@v4
with:
python-version: 3.12
- name: Query version with setuptools_scm
id: version
shell: bash
run: |
python -m pip install setuptools_scm
VERSION=$(python -c "from src.PyPop import __version_scheme__; import setuptools_scm; print(setuptools_scm.get_version(version_scheme=__version_scheme__))")
echo "VERSION=${VERSION}"
echo "VERSION=${VERSION}" >> $GITHUB_ENV
- name: Install toml and remove cffconvert from pyproject.toml
run: |
python -m pip install toml
python -c "
import toml
with open('pyproject.toml', 'r') as f:
config = toml.load(f)
if 'build-system' in config and 'requires' in config['build-system']:
config['build-system']['requires'] = [
dep for dep in config['build-system']['requires'] if 'cffconvert' not in dep.lower()
]
with open('pyproject.toml', 'w') as f:
toml.dump(config, f)
"
- name: Generate citation formats
run: |
python --version
python -m pip install git+https://github.com/alexlancaster/cffconvert.git@combine_features#egg=cffconvert
python src/PyPop/citation.py
- name: Build and test wheels
uses: pypa/[email protected]
env:
# FIXME: only run the slow tests when doing regular pushes, or manual - not for PRs
CIBW_TEST_COMMAND: "pytest -v {package}/tests ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && '--runslow' || '' }}"
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ env.VERSION }}
CIBW_ENVIRONMENT_PASS_LINUX: SETUPTOOLS_SCM_PRETEND_VERSION
with:
only: ${{ matrix.only }}
package-dir: .
Expand Down
6 changes: 3 additions & 3 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ url: http://pypop.org/
repository-artifact: https://pypi.org/project/pypop-genomics/
repository-code: https://github.com/alexlancaster/pypop
type: software
license: GPL-2.0-or-later
version: v1.1.1
doi: 10.5281/zenodo.13742984
keywords:
- population genetics
- population genomics
Expand All @@ -83,6 +86,3 @@ keywords:
- Major histocompatibility complex
- HLA
- MHC
license: GPL-2.0-or-later
version: v1.1.1
doi: 10.5281/zenodo.13742984
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include DEV_NOTES.md
include LICENSE
include NEWS.rst
include MANIFEST.in
include CITATION.cff
prune .github
prune website
prune data/*
Expand Down
74 changes: 49 additions & 25 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,55 @@ If you write a paper that uses PyPop in your analysis, please cite
`10.3389/fimmu.2024.1378512
<https://doi.org/10.3389/fimmu.2024.1378512>`__

* **and** the `Zenodo record <https://zenodo.org/records/10080667>`__
for the software. To cite the correct version, follow these steps:

1) First visit the DOI for the overall Zenodo record:
`10.5281/zenodo.10080667
<https://zenodo.org/doi/10.5281/zenodo.10080667>`__. This DOI
represents **all versions**, and will always resolve to the
latest one.

2) When you are viewing the record, look for the **Versions** box
in the right-sidebar. Here are listed all versions (including
older versions).

3) Select and click the version-specific DOI that matches the
specific version of PyPop that you used for your analysis.

4) Once you are visiting the Zenodo record for the specific version,
under the **Citation** box in the right-sidebar, select the
citation format you wish to use and click to copy the citation.
It will contain link to the version-specific DOI, and be of the
form:

Lancaster, AK et al. (YYYY) "PyPop: Python for Population
Genomics" (Version X.Y.Z) [Computer
software]. Zenodo. https://doi.org/10.5281/zenodo.XXXXX
* **and** a citation to the `Zenodo record
<https://zenodo.org/records/10080667>`__ which includes a DOI for
the version of the software you used in your analyses. Citing this
record and DOI supports reproducibility by allowing researchers to
to determine the exact version of PyPop used in any particular
analysis. In addition, it allows retrieval of long-term software
source-code archives, independent of the original developers.

Here's how to cite the correct version:

* If you have PyPop version 1.1.2 or later, currently installed, you
can run:

.. code-block:: shell

pypop --citation

which outputs the Zenodo record citation in the simple "APA"
format (you can also choose from BibTeX, EndNote, RIS and other
formats, see the section on `command-line interfaces
<http://pypop.org/docs/guide-chapter-usage.html#command-line-interfaces>`_
in the *User Guide* for more details).

* If you do not have PyPop installed, have a release of PyPop
earlier than 1.1.2, or otherwise want to obtain the DOI and
citation for specific versions, follow these steps:

1) First visit the DOI for the overall Zenodo record:
`10.5281/zenodo.10080667
<https://zenodo.org/doi/10.5281/zenodo.10080667>`__. This DOI
represents **all versions**, and will always resolve to the
latest one.

2) When you are viewing the record, look for the **Versions** box
in the right-sidebar. Here are listed all versions (including
older versions).

3) Select and click the version-specific DOI that matches the
specific version of PyPop that you used for your analysis.

4) Once you are visiting the Zenodo record for the specific version,
under the **Citation** box in the right-sidebar, select the
citation format you wish to use and click to copy the citation.
It will contain link to the version-specific DOI, and be of the
form:

Lancaster, AK et al. (YYYY) "PyPop: Python for Population
Genomics" (Version X.Y.Z) [Computer
software]. Zenodo. https://doi.org/10.5281/zenodo.XXXXX

Note that citation metadata for the current Zenodo record is also
stored in `CITATION.cff
Expand Down
23 changes: 15 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ skip = ["*-win32", "*_i686", # skip 32-bit builds
"cp313-musllinux_x86_64", # problem with this version
"cp36-musllinux_*", "cp37-musllinux_*", "cp38-musllinux_*"] # older musllinux missing numpy wheels
test-extras = ["test"]
test-command = "pytest -v {package}/tests"
# FIXME: add below test-command unit tests need to be saved
# "&& echo {package} && ls && tar zcvf unit_tests_output.tar.gz run_test_* && cp unit_tests_output.tar.gz {package}/wheelhouse/"

# Skip trying to test arm64 builds on Intel Macs as per
# https://cibuildwheel.readthedocs.io/en/stable/faq/#apple-silicon
# test-skip = "*-macosx_arm64 *-macosx_universal2:arm64"
# don't try and install pypi packages and build from source

# FIXME: can add "test-command" that would allow unit test output to be saved
# "pytest -v {package}/tests && echo {package} && ls && tar zcvf unit_tests_output.tar.gz run_test_* && cp unit_tests_output.tar.gz {package}/wheelhouse/"

# don't try and install pypi packages that need build from source
# this is mainly import during the testing phase
environment = { PIP_ONLY_BINARY=":all:" }

# use pip and override the PIP_ONLY_BINARY=:all: during wheel generation
# so that certain source-only build deps (like cffconvert) install
build-frontend = { name = "pip", args = ["--only-binary=:none:"] }

[[tool.cibuildwheel.overrides]]
# for latest CPython use newer manylinux image
select = "cp312-*linux*"
Expand Down Expand Up @@ -93,10 +95,15 @@ select ="*-win_*"
inherit.environment="append"
environment = { CPATH="gsl-msvc14-x64.2.3.0.2779\\\\build\\\\native", LIBRARY_PATH="gsl-msvc14-x64.2.3.0.2779\\\\build\\\\native\\\\static" }

[tool.setuptools_scm]
write_to = "src/PyPop/_version.py" # matches the path where version will be written

[build-system]
build-backend = "setuptools.build_meta:__legacy__"
requires = ["setuptools>=42",
"setuptools_scm[toml]>=6.2",
"cffconvert @ git+https://github.com/alexlancaster/cffconvert.git@combine_features#egg=cffconvert",
"importlib-metadata; python_version <= '3.8'"
]


41 changes: 36 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
from glob import glob
from setuptools import setup
from setuptools.extension import Extension
from setuptools.command.build_py import build_py as _build_py
from setuptools.command.install import install as _install
from distutils.command import clean
from sysconfig import _PREFIX, get_config_vars, get_config_var
from src.PyPop import __pkgname__, __version_scheme__
Expand Down Expand Up @@ -210,10 +212,36 @@ def path_to_src(source_path_list):
# don't include HWEEnum
# extensions.append(ext_HweEnum)

data_file_paths = []
xslt_data_file_paths = []
# xslt files are in a subdirectory
xslt_files = [f + '.xsl' for f in ['text', 'html', 'lib', 'common', 'filter', 'hardyweinberg', 'homozygosity', 'emhaplofreq', 'meta-to-tsv', 'sort-by-locus', 'haplolist-by-group', 'phylip-allele', 'phylip-haplo']]
data_file_paths.extend(xslt_files)
xslt_data_file_paths.extend(xslt_files)

citation_data_file_paths = []
# citation files are in a subdirectory of PyPop, but not a separate module
from src.PyPop.citation import citation_output_formats, convert_citation_formats
citation_files = [os.path.join("citation", 'CITATION.' + suffix) for suffix in citation_output_formats]
citation_data_file_paths.extend(citation_files)

# currently disabled (these are built in a github action)
class CustomBuildPy(_build_py):
def run(self):

# do standard build process
super().run()

# if not running from a CIBUILDWHEEL environment variable
# we need to create the citations
if os.environ.get('CIBUILDWHEEL') != '1':

# source citation path (single-source of truth)
citation_path = "CITATION.cff"

# then copy CITATION.cff to temp build directory
# use setuptools' temp build directory
build_lib = self.get_finalized_command('build').build_lib

convert_citation_formats(build_lib, citation_path)

# read the contents of your README file
from pathlib import Path
Expand Down Expand Up @@ -250,7 +278,8 @@ def path_to_src(source_path_list):
],
package_dir = {"": src_dir},
packages = ["PyPop", "PyPop.xslt"],
package_data={"PyPop.xslt": data_file_paths},
package_data = {"PyPop.xslt": xslt_data_file_paths,
"PyPop": citation_data_file_paths},
install_requires = ["numpy <= 2.1.3",
"lxml <= 5.3.0",
"importlib-resources; python_version <= '3.8'",
Expand All @@ -265,6 +294,8 @@ def path_to_src(source_path_list):
'pypop-interactive=PyPop.pypop:main_interactive']
},
ext_modules=extensions,
cmdclass={'clean': CleanCommand,},
cmdclass={'clean': CleanCommand,
# enable the custom build
'build_py': CustomBuildPy,
},
)

38 changes: 36 additions & 2 deletions src/PyPop/CommandLineInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@
# UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

import os, sys
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, RawDescriptionHelpFormatter, FileType
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, RawDescriptionHelpFormatter, FileType, Action
from pathlib import Path
from PyPop import platform_info # global info
from PyPop import platform_info # global info
from PyPop.citation import citation_output_formats # and citation formats

"""Command-line interface for PyPop scripts
"""
Expand All @@ -45,13 +46,46 @@
class PyPopFormatter(ArgumentDefaultsHelpFormatter, RawDescriptionHelpFormatter):
pass

class CitationAction(Action):

def __call__(self, parser, namespace, values, option_string=None):

citation_format = values or 'apalike'
citation_file_name = f'citation/CITATION.{citation_format}'

try: # looking in installed package
from importlib.resources import files
citation_file = files('PyPop').joinpath(citation_file_name)
citation_text = citation_file.read_text()
except (ModuleNotFoundError, ImportError, FileNotFoundError): # fallback to using backport if not found
try:
from importlib_resources import files
citation_file = files('PyPop').joinpath(citation_file_name)
citation_text = citation_file.read_text()
except (ModuleNotFoundError, ImportError, FileNotFoundError): # fallback to looking in top-level directory if running from repo
top_level_dir = Path(__file__).resolve().parent.parent.parent
citation_file = top_level_dir / 'CITATION.cff' # only output CFF

if citation_file.exists():
print("only CITATION.cff is available")
print()
citation_text = citation_file.read_text()
else:
print("could not locate the specified citation format.")
parser.exit()

print(citation_text)
parser.exit() # exit after printing the file

def get_parent_cli(version="", copyright_message=""):
# options common to both scripts
parent_parser = ArgumentParser(add_help=False)

# define function arguments as signatures - need to be added in child parser as part of the selection logic
common_args = [
(["-h", "--help"], {'action': "help", 'help': "show this help message and exit"}),
(["--citation"], {'help': "generate citation to PyPop for this version of PyPop",
'action': CitationAction, 'nargs':'?', 'choices': citation_output_formats, 'default':'apalike'}),
(["-o", "--outputdir"], {'help':"put output in directory OUTPUTDIR",
'required':False, 'type':Path, 'default':None}),
(["-V", "--version"], {'action':'version',
Expand Down
Loading
Loading