From 61606b6dd99feddb3eb412da59ca94c7493ef279 Mon Sep 17 00:00:00 2001 From: Becky Sweger Date: Fri, 11 Oct 2024 21:51:55 -0400 Subject: [PATCH 1/8] Add readthedocs and sphinx to cladetime This is cladetime's MVP documentation. Most of the changes are in the docs/ folder which contains readthedocs and sphinx configuration, as well as the documentation pages written in restructured text. Out of scope: hosting on GitHub pages, CI/CD publishing and previews. The goal of this change is to give early users enough information to get started. --- .readthedocs.yaml | 21 ++++ docs/_static/cladetime_logo_dark_mode.png | Bin 0 -> 20801 bytes docs/_static/cladetime_logo_light_mode.png | Bin 0 -> 20458 bytes docs/_static/reichlab.png | Bin 0 -> 18468 bytes docs/_static/reichlab_favicon.png | Bin 0 -> 3900 bytes docs/conf.py | 137 +++++++++++++++++++++ docs/index.rst | 68 ++++++++++ docs/reference/cladetime.rst | 8 ++ docs/reference/index.rst | 6 + docs/user-guide.rst | 91 ++++++++++++++ pyproject.toml | 17 ++- src/cladetime/cladetime.py | 104 ++++++++++------ 12 files changed, 412 insertions(+), 40 deletions(-) create mode 100644 .readthedocs.yaml create mode 100644 docs/_static/cladetime_logo_dark_mode.png create mode 100644 docs/_static/cladetime_logo_light_mode.png create mode 100644 docs/_static/reichlab.png create mode 100644 docs/_static/reichlab_favicon.png create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/reference/cladetime.rst create mode 100644 docs/reference/index.rst create mode 100644 docs/user-guide.rst diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..476326b --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,21 @@ +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.12" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py + fail_on_warning: true + +python: + install: + - method: pip + path: . + extra_requirements: + - docs diff --git a/docs/_static/cladetime_logo_dark_mode.png b/docs/_static/cladetime_logo_dark_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..2129dc5a99dc4f346eef99070ad5c7c0402608d2 GIT binary patch literal 20801 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 X_$ZfOjGE}T00000NkvXXu0mjf%f9ad literal 0 HcmV?d00001 diff --git a/docs/_static/cladetime_logo_light_mode.png b/docs/_static/cladetime_logo_light_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..808dc5b185d05cc5e5b7d587abb3fe3fbf5d4cca GIT binary patch literal 20458 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 literal 0 HcmV?d00001 diff --git a/docs/_static/reichlab.png b/docs/_static/reichlab.png new file mode 100644 index 0000000000000000000000000000000000000000..b372c613c3275fb48026334172da981bae943417 GIT binary patch literal 18468 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 Y2l^MIUtvwADgXcg07*qoM6N<$f_UfW=>Px# literal 0 HcmV?d00001 diff --git a/docs/_static/reichlab_favicon.png b/docs/_static/reichlab_favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..3cce4ff3c6b1246ef5428b622497e58c38124f7d GIT binary patch literal 3900 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 literal 0 HcmV?d00001 diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..8c79c0c --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,137 @@ +import os +import sys +from datetime import date + +# Configuration file for the Sphinx documentation builder. + +# -- Project information + +project = "Cladetime" +project_copyright = f"{date.today().year}, Reich Lab @ The University of Massachusetts Amherst" +author = "Reich Lab" + +# Add cladetime location to the path, so we can use autodoc to +# generate API documentation from docstrings. +root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +sys.path.insert(0, root_path) + +release = "0.1" +# FIXME: get the version dynamically +version = "0.1.0" + +# -- General configuration + +extensions = [ + "myst_parser", + "sphinx.ext.autodoc", + "sphinx_copybutton", + "sphinx.ext.doctest", + "sphinx.ext.intersphinx", + "sphinx_github_style", + "sphinxext.opengraph", + "sphinx.ext.napoleon", +] + +intersphinx_mapping = { + "python": ("https://docs.python.org/3/", None), + "sphinx": ("https://www.sphinx-doc.org/en/master/", None), + "polars": ("https://docs.pola.rs/api/python/stable", None), +} +intersphinx_disabled_domains = ["std"] + +# Copied these settings from the copybutton's config +# https://github.com/executablebooks/sphinx-copybutton/blob/master/docs/conf.py +copybutton_prompt_text = r">>> |\.\.\. |\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: " +copybutton_prompt_is_regexp = True +copybutton_line_continuation_character = "\\" +copybutton_here_doc_delimiter = "EOT" +copybutton_selector = "div:not(.no-copybutton) > div.highlight > pre" + +templates_path = ["_templates"] + +# The root toctree document. +root_doc = "index" + +# Test code blocks only when explicitly specified +doctest_test_doctest_blocks = "" + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_static_path = ["_static"] +html_theme = "furo" +html_favicon = "_static/reichlab_favicon.png" +html_title = "Cladetime" +html_last_updated_fmt = "%Y-%m-%d" + +# Settings for the GitHub link extension +linkcode_url = "https://github.com/reichlab/cladetime" + +# These folders are copied to the documentation's HTML output +html_theme_options = { + "announcement": """ + + Cladetime is a work in progress. Please feel free to file issues on GitHub. + + """, + "sidebar_hide_name": True, + "light_logo": "cladetime_logo_light_mode.png", + "dark_logo": "cladetime_logo_dark_mode.png", + "navigation_with_keys": True, + "source_repository": "https://github.com/reichlab/cladetime/", + # source for GitHub footer icon: + # https://pradyunsg.me/furo/customisation/footer/#using-embedded-svgs + "footer_icons": [ + { + "name": "GitHub", + "url": "https://github.com/reichlab/cladetime", + "html": """ + + + + """, + "class": "", + }, + ], +} + +# from https://myst-parser.readthedocs.io/en/latest/syntax/optional.html +myst_enable_extensions = [ + "amsmath", + "deflist", + "dollarmath", + "fieldlist", + "substitution", + "tasklist", + "colon_fence", + "attrs_inline", +] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "friendly" + +# Show typehints as content of the function or method +autodoc_typehints = "description" +autodoc_member_order = "bysource" + +# Open Graph metadata +ogp_site_url = "https://cladetime.readthedocs.io" +ogp_title = "cladetime documentation" +ogp_type = "website" +ogp_image = "https://cladetime.readthedocs.io/en/latest/_static/cladetime_logo_light_mode.png" +ogp_social_cards = { + "image": "https://cladetime.readthedocs.io/en/latest/_static/cladetime_logo_light_mode.png", + "line_color": "#5d9c9c", +} + +# Warn about all references to unknown targets +nitpicky = True +nitpick_ignore = [ + ("py:class", "datetime"), + ("py:class", "polars.LazyFrame"), + ("py:class", "polars.lazyframe.frame.LazyFrame"), +] + + +# -- Options for EPUB output +epub_show_urls = "footnote" diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..62fecfc --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,68 @@ +:og:description: Cladetime is a Python interface for accessing Sars-Cov-2 sequence and clade data provided by Nextstrain. + +=============== + Cladetime +=============== + +Cladetime is a Python interface for accessing `Nextstrain `_ Sars-Cov-2 sequence and clade data. + +.. toctree:: + :titlesonly: + :hidden: + + Home + user-guide + reference/index + +Installation +------------ + +Cladetime can be installed with `pip `_: + +.. code-block:: bash + + $ pip install git+https://github.com/reichlab/cladetime.git + + +Usage +----- + +The CladeTime :any:`CladeTime` class provides a lightweight wrapper around historical and current +SARS-CoV-2 GenBank sequence and sequence metadata created by `nextstrain.org's `_ +daily workflow pipeline. + +.. code-block:: python + + >>> import polars as pl + >>> from cladetime import CladeTime + + >>> ct = CladeTime() + >>> filtered_sequence_metadata = ( + ... ct.sequence_metadata.select(["country", "division", "date", "host", "clade_nextstrain"]) + ... .filter( + ... pl.col("country") == "USA", + ... pl.col("date").is_not_null(), + ... pl.col("host") == "Homo sapiens", + ... ) + ... .cast({"date": pl.Date}, strict=False) + ... ) + + >>> filtered_sequence_metadata.head(5).collect() + + shape: (5, 5) + ┌─────────┬──────────┬────────────┬──────────────┬──────────────────┐ + │ country ┆ division ┆ date ┆ host ┆ clade_nextstrain │ + │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ + │ str ┆ str ┆ date ┆ str ┆ str │ + ╞═════════╪══════════╪════════════╪══════════════╪══════════════════╡ + │ USA ┆ Alabama ┆ 2022-07-07 ┆ Homo sapiens ┆ 22A │ + │ USA ┆ Arizona ┆ 2022-07-02 ┆ Homo sapiens ┆ 22B │ + │ USA ┆ Arizona ┆ 2022-07-19 ┆ Homo sapiens ┆ 22B │ + │ USA ┆ Arizona ┆ 2022-07-15 ┆ Homo sapiens ┆ 22B │ + │ USA ┆ Arizona ┆ 2022-07-20 ┆ Homo sapiens ┆ 22B │ + └─────────┴──────────┴────────────┴──────────────┴──────────────────┘ + +See the :doc:`user-guide` for more details about working with Cladetime. + +The :doc:`reference/index` documentation provides API-level documentation. + diff --git a/docs/reference/cladetime.rst b/docs/reference/cladetime.rst new file mode 100644 index 0000000..35d1615 --- /dev/null +++ b/docs/reference/cladetime.rst @@ -0,0 +1,8 @@ +:og:description: Cladetime is a Python interface for accessing Sars-Cov-2 sequence and clade data provided by Nextstrain. + +========== +CladeTime +========== + +.. autoclass:: cladetime.CladeTime + :members: diff --git a/docs/reference/index.rst b/docs/reference/index.rst new file mode 100644 index 0000000..7660209 --- /dev/null +++ b/docs/reference/index.rst @@ -0,0 +1,6 @@ +API Reference +============= + +.. toctree:: + + cladetime diff --git a/docs/user-guide.rst b/docs/user-guide.rst new file mode 100644 index 0000000..3087bc1 --- /dev/null +++ b/docs/user-guide.rst @@ -0,0 +1,91 @@ +=============== +User Guide +=============== + + + +Finding Nextstrain SARS-CoV-2 sequences and sequence metadata +-------------------------------------------------------------- + +Cladetime provides a CladeTime class that provides a lightweight interface to nextstrain.org files. + +.. code-block:: python + + >>> from cladetime import CladeTime + + # Instantiating a CladeTime object with no parameters will use the + # latest available data from nextstrain.org. + >>> ct = CladeTime() + + # URL to the most recent SARS-CoV-2 sequence file (.fasta) + >>> ct.url_sequence + https://nextstrain-data.s3.amazonaws.com/files/ncov/open/sequences.fasta.zst?versionId=d66Hn1T0eFMAg8osEh8Yrod.QEUBRxvu' + + # URL to the metadata that describes the sequences in the above file + >>> ct.url.sequence_metadata + 'https://nextstrain-data.s3.amazonaws.com/files/ncov/open/metadata.tsv.zst?versionId=JTXXFlKyyvt9AerxKMwoZflhFYQFrDek' + + # Metadata about the nextstrain data pipeline that created generated the sequence file and its metadata + >>> ct.ncov_metadata + {'schema_version': 'v1', + 'nextclade_version': 'nextclade 3.8.2', + 'nextclade_dataset_name': 'SARS-CoV-2', + 'nextclade_dataset_version': '2024-09-25--21-50-30Z', + 'nextclade_tsv_sha256sum': '5b0f2b64bfe694a3c96bd5a116de8fae23b144bfd3d22da774d4bfe9a84399c3', + 'metadata_tsv_sha256sum': '1dc6a4204039e5c69eed84583faf75bbec1629e531dc99aab5bd566d3fb28295'} + + +Working with SARS-CoV-2 sequence metadata +------------------------------------------ + +The CladeTime class also provides a Polars LazyFrame object that points to the Nextstrain's sequence metadata file. +This file is in .tsv format and contains information about the sequences, such as their collection date, +host, and location. + +The metadata also includes a clade assignment for each sequence. Nextstrain assigns clades based on a reference tree, +and the reference tree varies over time. + +.. code-block:: python + + >>> import polars as pl + >>> from cladetime import CladeTime + + >>> ct = CladeTime() + + # ct contains a Polars LazyFrame that references the sequence metadata .tsv file on AWS S3 + >>> lf = ct.sequence_metadata + >>> lf + + + +Getting historical SARS-CoV-2 sequence metadata +------------------------------------------------ + +A CladeTime instance created without parameters will reference the most +recent data available from Nextstrain. + +To access sequence metadata at a specific point in time, pass a date string +in the format 'YYYY-MM-DD' to the CladeTime constructor. Alternately, you pass +a Python datetime object. Both will be treated as UTC dates/times. + +.. code-block:: python + + >>> from cladetime import CladeTime + + >>> ct = CladeTime(sequence_as_of="2024-08-02") + + # ct operations now reference the version of the sequence metadata + # that was available at midnight UTC on August 2, 2024. + >>> ct.sequence_metadata \ + ... .cast({"date": pl.Date}, strict=False) \ + ... .select(pl.max("date")).collect() + + shape: (1, 1) + ┌────────────┐ + │ date │ + │ --- │ + │ date │ + ╞════════════╡ + │ 2024-07-23 │ + └────────────┘ + diff --git a/pyproject.toml b/pyproject.toml index 260fd1c..74c8192 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,11 @@ authors = [ requires-python = ">=3.11" readme = "README.md" -license = {text = "MIT"} + +classifiers = [ + "Development Status :: 3 - Alpha", + "License :: OSI Approved :: MIT License", +] dependencies = [ "awscli>=1.32.92", @@ -41,9 +45,20 @@ dev = [ "types-python-dateutil", "types-requests", ] +docs = [ + "furo", + "matplotlib", + "myst-parser", + "sphinx>=5.0,<6.0", + "sphinx-copybutton", + "sphinx-github-style", + "sphinxext-opengraph", + ] [project.urls] Repository = "https://github.com/reichlab/cladetime.git" +Documentation = "https://cladetime.readthedocs.io/" +Issues = "https://github.com/reichlab/cladetime/issues" [project.entry-points."console_scripts"] assign_clades = "cladetime.assign_clades:main" diff --git a/src/cladetime/cladetime.py b/src/cladetime/cladetime.py index d3b108d..0223b60 100644 --- a/src/cladetime/cladetime.py +++ b/src/cladetime/cladetime.py @@ -15,51 +15,45 @@ class CladeTime: - """ - Wrapper around Nextstrain/Nextclade tooling to generate Sars-CoV-2 genome clade assignments - and aggregations at a specific point in time. CladeTime operates on Genbank sequences. + """Interface for Nextstrain Sars-CoV-2 genome sequences and clades. + + The CladeTime class is instantiated with two optional arguments that + specify the point in time at which to access genome sequences/metadata + as well as the reference tree used for clade assignment. CladeTime + interacts with GenBank-based data provided by the Nextstrain project. + + Parameters + ---------- + sequence_as_of : datetime.datetime | str | None + Sets the versions of Nextstrain SAR-CoV-2 genome sequence + and sequence metadata files that will be used by + CladeTime properties and methods. Can be a datetime object or a + string in YYYY-MM-DD format, both of which will be treated as + UTC. The default value is midnight of the current UTC date. + tree_as_of : datetime.datetime | str | None + Sets the version of the Nextstrain reference tree that will be + used by CladeTime. Can be a datetime object or a string in + YYYY-MM-DD format, both of which will be treated as UTC. + The default value is :any:`sequence_as_of` Attributes ---------- - sequence_as_of : datetime - Use the NextStrain sequences and sequence metadata that were available - as of this date and time (UTC). - ncov_metadata : dict - Metadata for the Nextstrain ncov pipeline that generated the sequence and - sequence metadata that correspond to the sequence_as_of date. - metadata_metadata : pl.LazyFrame - A Polars lazyframe reference to url_sequence_metadata. - tree_as_of : datetime - Use the NextStrain reference tree that was available as of this - date and time (UTC). - Can be a datetime object, a string in the format - "YYYY-MM-DD", or None (which defaults to the current date and time). - url_ncov_metadata: str - S3 URL to the Nextstrain ncov metadata file (.json) + url_ncov_metadata : str + S3 URL to metadata from the Nextstrain pipeline run that + generated the sequence clade assignments in + :any:`url_sequence_metadata` url_sequence : str S3 URL to the Nextstrain Sars-CoV-2 sequence file (zst-compressed - .fasta) that was available at the sequence_as_of. + .fasta) that was current at the date specified in + :any:`sequence_as_of` url_sequence_metadata : str S3 URL to the Nextstrain Sars-CoV-2 sequence metadata file - (zst-compressed tsv) that was available at the sequence_as_of. + (zst-compressed tsv) that was current at the date specified in + :any:`sequence_as_of` """ def __init__(self, sequence_as_of=None, tree_as_of=None): - """ - Parameters - ---------- - sequence_as_of : datetime | str | None, default = now() - Use the NextStrain sequences and sequence metadata that were available - as of this date. Can be a datetime object, a string in the format - "YYYY-MM-DD", or None (which defaults to the current date and time). - CladeTime treats all dates and times as UTC. - tree_as_of : datetime | str | None, default = now() - Use the NextStrain reference tree that was available as of this date. - Can be a datetime object, a string in the format - "YYYY-MM-DD", or None (which defaults to the sequence_as_of date). - CladeTime treats all dates and times as UTC. - """ - + """CladeTime constructor.""" self._config = self._get_config() self.sequence_as_of = sequence_as_of self.tree_as_of = tree_as_of @@ -83,11 +77,16 @@ def __init__(self, sequence_as_of=None, tree_as_of=None): @property def sequence_as_of(self) -> datetime: + """ + datetime.datetime : The date and time (UTC) used to retrieve NextStrain sequences + and sequence metadata. :any:`url_sequence` and + :any:`url_sequence_metadata` link to + Nextstrain files that were current as of this date. + """ return self._sequence_as_of @sequence_as_of.setter def sequence_as_of(self, date) -> None: - """Set the sequence_as_of attribute.""" sequence_as_of = self._validate_as_of_date(date) utc_now = datetime.now(timezone.utc) if sequence_as_of > utc_now: @@ -101,11 +100,16 @@ def sequence_as_of(self, date) -> None: @property def tree_as_of(self) -> datetime: + """ + datetime.datetime : The date and time (UTC) used to retrieve the NextStrain + reference tree. :any:`get_reference_tree` + uses this date to get the reference tree that was current as + of this date. + """ return self._tree_as_of @tree_as_of.setter def tree_as_of(self, date) -> None: - """Set the tree_as_of attribute.""" if date is None: tree_as_of = self.sequence_as_of else: @@ -126,7 +130,12 @@ def ncov_metadata(self): @ncov_metadata.getter def ncov_metadata(self) -> dict: - """Get the ncov_metadata attribute.""" + """ + dict : Metadata for the reference tree that was used for SARS-CoV-2 + clade assignments as of :any:`tree_as_of`. + This property will be empty for dates before 2024-08-01, when + Nextstrain began publishing ncov pipeline metadata. + """ if self.url_ncov_metadata: metadata = _get_ncov_metadata(self.url_ncov_metadata) return metadata @@ -140,7 +149,10 @@ def sequence_metadata(self): @sequence_metadata.getter def sequence_metadata(self) -> pl.LazyFrame: - """Get the sequence_metadata attribute.""" + """ + :class:`polars.LazyFrame` : A Polars LazyFrame that references + :any:`url_sequence_metadata` + """ if self.url_sequence_metadata: sequence_metadata = get_covid_genome_metadata(metadata_url=self.url_sequence_metadata) return sequence_metadata @@ -182,3 +194,17 @@ def _validate_as_of_date(self, as_of: str) -> datetime: raise CladeTimeInvalidDateError(f"Date must be after May 1, 2023: {as_of_date}") return as_of_date + + def get_reference_tree(self) -> dict: + """Return a reference tree used for SARS-CoV-2 clade assignments + + Retrieves the reference tree that was current as of + :any:`tree_as_of`. + + This method is not yet implemented. + + Returns + ------- + dict + """ + return {self.tree_as_of: "not implemented"} From 36028c17bfe305025a5932cf68b55bf2135b4a31 Mon Sep 17 00:00:00 2001 From: Becky Sweger Date: Wed, 16 Oct 2024 14:42:10 -0500 Subject: [PATCH 2/8] Update docs/index.rst Co-authored-by: Evan Ray --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 62fecfc..fff7c50 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,4 +1,4 @@ -:og:description: Cladetime is a Python interface for accessing Sars-Cov-2 sequence and clade data provided by Nextstrain. +:og:description: Cladetime is a Python interface for accessing SARS-CoV-2 sequence and clade data provided by Nextstrain. =============== Cladetime From b81e715fa10e252bfdecccde1d0ad40688789561 Mon Sep 17 00:00:00 2001 From: Becky Sweger Date: Wed, 16 Oct 2024 14:42:20 -0500 Subject: [PATCH 3/8] Update docs/index.rst Co-authored-by: Evan Ray --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index fff7c50..bc25652 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,7 +4,7 @@ Cladetime =============== -Cladetime is a Python interface for accessing `Nextstrain `_ Sars-Cov-2 sequence and clade data. +Cladetime is a Python interface for accessing `Nextstrain `_ SARS-CoV-2 sequence and clade data. .. toctree:: :titlesonly: From 13b8fd03efd9b5a85dcedf7284ab485979612320 Mon Sep 17 00:00:00 2001 From: Becky Sweger Date: Wed, 16 Oct 2024 14:42:27 -0500 Subject: [PATCH 4/8] Update docs/user-guide.rst Co-authored-by: Evan Ray --- docs/user-guide.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user-guide.rst b/docs/user-guide.rst index 3087bc1..1d64128 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -65,7 +65,7 @@ A CladeTime instance created without parameters will reference the most recent data available from Nextstrain. To access sequence metadata at a specific point in time, pass a date string -in the format 'YYYY-MM-DD' to the CladeTime constructor. Alternately, you pass +in the format 'YYYY-MM-DD' to the CladeTime constructor. Alternatively, you can pass a Python datetime object. Both will be treated as UTC dates/times. .. code-block:: python From c92e4aec804d05f134c49c0fe450bebe21dd7ad7 Mon Sep 17 00:00:00 2001 From: Becky Sweger Date: Wed, 16 Oct 2024 14:42:38 -0500 Subject: [PATCH 5/8] Update docs/user-guide.rst Co-authored-by: Evan Ray --- docs/user-guide.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/user-guide.rst b/docs/user-guide.rst index 1d64128..fb1f6aa 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -66,7 +66,10 @@ recent data available from Nextstrain. To access sequence metadata at a specific point in time, pass a date string in the format 'YYYY-MM-DD' to the CladeTime constructor. Alternatively, you can pass -a Python datetime object. Both will be treated as UTC dates/times. +a Python datetime object. Both will be treated as UTC dates/times. If a date string +is specified, the datetime will be set to 00:00:00 hours:minutes:seconds on that +date, meaning that the CladeTime object will retrieve the sequence metadata that +was available at the start of that day. .. code-block:: python From eb87b8edd68327cda58b74472feb3d3108b019c8 Mon Sep 17 00:00:00 2001 From: Becky Sweger Date: Wed, 16 Oct 2024 14:42:44 -0500 Subject: [PATCH 6/8] Update src/cladetime/cladetime.py Co-authored-by: Evan Ray --- src/cladetime/cladetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cladetime/cladetime.py b/src/cladetime/cladetime.py index 0223b60..35b2095 100644 --- a/src/cladetime/cladetime.py +++ b/src/cladetime/cladetime.py @@ -15,7 +15,7 @@ class CladeTime: - """Interface for Nextstrain Sars-CoV-2 genome sequences and clades. + """Interface for Nextstrain SARS-CoV-2 genome sequences and clades. The CladeTime class is instantiated with two optional arguments that specify the point in time at which to access genome sequences/metadata From b0ce3750d6cef65aff027ad0b7d032db1cf1ebaf Mon Sep 17 00:00:00 2001 From: Becky Sweger Date: Wed, 16 Oct 2024 14:42:54 -0500 Subject: [PATCH 7/8] Update src/cladetime/cladetime.py Co-authored-by: Evan Ray --- src/cladetime/cladetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cladetime/cladetime.py b/src/cladetime/cladetime.py index 35b2095..048814c 100644 --- a/src/cladetime/cladetime.py +++ b/src/cladetime/cladetime.py @@ -25,7 +25,7 @@ class CladeTime: Parameters ---------- sequence_as_of : datetime.datetime | str | None - Sets the versions of Nextstrain SAR-CoV-2 genome sequence + Sets the versions of Nextstrain SARS-CoV-2 genome sequence and sequence metadata files that will be used by CladeTime properties and methods. Can be a datetime object or a string in YYYY-MM-DD format, both of which will be treated as From 412d26e2ae50daef6e85497d167da4a8799435de Mon Sep 17 00:00:00 2001 From: Becky Sweger Date: Thu, 17 Oct 2024 12:18:35 -0500 Subject: [PATCH 8/8] Update src/cladetime/cladetime.py Co-authored-by: Evan Ray --- src/cladetime/cladetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cladetime/cladetime.py b/src/cladetime/cladetime.py index 048814c..47a2589 100644 --- a/src/cladetime/cladetime.py +++ b/src/cladetime/cladetime.py @@ -29,7 +29,7 @@ class CladeTime: and sequence metadata files that will be used by CladeTime properties and methods. Can be a datetime object or a string in YYYY-MM-DD format, both of which will be treated as - UTC. The default value is midnight of the current UTC date. + UTC. The default value is the current time. tree_as_of : datetime.datetime | str | None Sets the version of the Nextstrain reference tree that will be used by CladeTime. Can be a datetime object or a string in