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 unit-test cases for pypots-cli #72

Merged
merged 35 commits into from
Apr 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
56cf848
doc: update the documentation configs and doc itself;
WenjieDu Apr 19, 2023
3f5dd7d
fix: try to fix Makefile;
WenjieDu Apr 19, 2023
0d9c579
fix: fix `ModuleNotFoundError: No module named 'pypots'` and avoid PE…
WenjieDu Apr 19, 2023
e11a8d1
feat: update the dependencies;
WenjieDu Apr 19, 2023
ad63280
feat: update the dependencies;
WenjieDu Apr 19, 2023
b8ad123
feat: add readthedocs config file;
WenjieDu Apr 19, 2023
99228f0
fix: update readthedocs config file;
WenjieDu Apr 19, 2023
552cb8c
refactor: delete docs/requirements.txt;
WenjieDu Apr 19, 2023
d335a11
doc: remove inherited-members in docs;
WenjieDu Apr 19, 2023
6243359
doc: exclude normrnd in pypots.forecasting.bttf;
WenjieDu Apr 19, 2023
589f99d
fix: update readthedocs config file;
WenjieDu Apr 19, 2023
0b16044
fix: remove html to fix error `Invalid "formats": expected one of (ht…
WenjieDu Apr 19, 2023
97671aa
fix: disable fail_on_warning;
WenjieDu Apr 19, 2023
6d47de5
doc: try to remove `exclude-members`;
WenjieDu Apr 19, 2023
c772bee
Merge branch 'dev' into doc
WenjieDu Apr 19, 2023
43354f0
Merge branch 'dev' into doc
WenjieDu Apr 21, 2023
1c71f4b
doc: update README;
WenjieDu Apr 21, 2023
d3f9e31
doc: update badges in README;
WenjieDu Apr 21, 2023
098325d
Merge branch 'dev' into doc
WenjieDu Apr 22, 2023
057a853
refactor: move `pypots-cli` from pypots/utils/commands to pypots/cli;
WenjieDu Apr 22, 2023
7697237
feat: add test cases for pypots-cli;
WenjieDu Apr 22, 2023
48e4855
feat: add test_cli.py into the execution of workflow CI;
WenjieDu Apr 22, 2023
a51bd93
fix: raise RuntimeError when enable strict mode in check_if_under_roo…
WenjieDu Apr 22, 2023
83cbec9
fix: try to use environment-dev.yml for testing env building;
WenjieDu Apr 23, 2023
3352b89
fix: remove installed pypots but keep dependencies;
WenjieDu Apr 23, 2023
418108b
feat: update environment_for_conda_test.yml;
WenjieDu Apr 23, 2023
5096b53
fix: capture RuntimeError;
WenjieDu Apr 23, 2023
3a49bd6
fix: only run installation command again if necessary;
WenjieDu Apr 23, 2023
05b1e44
fix: implement time out with threading;
WenjieDu Apr 23, 2023
65ecc5a
fix: directly set SPHINX_APIDOC_OPTIONS with os.environ to avoid bugs…
WenjieDu Apr 23, 2023
93da28d
fix: append "+cpu" if torch is not cuda version;
WenjieDu Apr 23, 2023
1c6e7da
fix: `pip install -e` error on Windows platform;
WenjieDu Apr 23, 2023
dd10fde
fix: log and ignore error raised when testing on Windows;
WenjieDu Apr 23, 2023
fbd6ae6
fix: log and ignore error raised when testing on Windows;
WenjieDu Apr 23, 2023
17091ae
fix: remove raising RuntimeError;
WenjieDu Apr 23, 2023
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
7 changes: 4 additions & 3 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ jobs:

- name: Test with pytest
run: |
# run tests separately here due to Segmentation Fault in test_clustering when run all in
# run tests separately here due to Segmentation Fault in test_clustering when run all in
# one command with `pytest` on MacOS. Bugs not caught, so this is a trade-off to avoid SF.
python -m pytest -rA pypots/tests/test_classification.py -n auto --cov=pypots --dist=loadgroup
python -m pytest -rA pypots/tests/test_classification.py -n auto --cov=pypots --dist=loadgroup
python -m pytest -rA pypots/tests/test_imputation.py -n auto --cov=pypots --cov-append --dist=loadgroup
python -m pytest -rA pypots/tests/test_clustering.py -n auto --cov=pypots --cov-append --dist=loadgroup
python -m pytest -rA pypots/tests/test_forecasting.py -n auto --cov=pypots --cov-append --dist=loadgroup
python -m pytest -rA pypots/tests/test_data.py -n auto --cov=pypots --cov-append --dist=loadgroup
python -m pytest -rA pypots/tests/test_utils.py -n auto --cov=pypots --cov-append --dist=loadgroup
python -m pytest -rA pypots/tests/test_cli.py -n auto --cov=pypots --cov-append --dist=loadgroup

- name: Generate the LCOV report
run: |
Expand All @@ -58,4 +59,4 @@ jobs:
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: 'coverage.lcov'
path-to-lcov: 'coverage.lcov'
40 changes: 25 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
**<p align="center">A Python Toolbox for Data Mining on Partially-Observed Time Series</p>**

<p align="center">
<img alt="Python version" src="https://img.shields.io/badge/Python->v3.6-yellow?color=88ada6">
<img alt="powered by Pytorch" src="https://img.shields.io/static/v1?label=PyTorch&message=%E2%9D%A4%EF%B8%8F&color=bbcdc5&logo=pytorch">
<img alt="Python version" src="https://img.shields.io/badge/Python-v3.7--3.10-88ada6?logo=python&logoColor=white">
<img alt="powered by Pytorch" src="https://img.shields.io/badge/PyTorch-%E2%9D%A4%EF%B8%8F-bbcdc5?logo=pytorch&logoColor=white">
<a href="https://pypi.org/project/">
<img alt="the latest release version" src="https://img.shields.io/github/v/release/wenjiedu/pypots?color=e0eee8&include_prereleases&label=Release">
</a>
<a href="https://github.com/WenjieDu/PyPOTS/blob/main/LICENSE">
<img alt="GPL3 license" src="https://img.shields.io/badge/License-GPL--v3-c0ebd7">
</a>
<a href="https://join.slack.com/t/pypots-dev/shared_invite/zt-1gq6ufwsi-p0OZdW~e9UW_IA4_f1OfxA">
<img alt="Slack Workspace" src="https://img.shields.io/badge/Slack-PyPOTS-grey?logo=slack&color=7bcfa6">
<img alt="Slack Workspace" src="https://img.shields.io/badge/Slack-PyPOTS-7bcfa6?logo=slack">
</a>
<a href="https://github.com/sponsors/WenjieDu">
<img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/wenjiedu?label=Sponsors&color=7fecad&logo=githubsponsors">
Expand All @@ -30,18 +30,19 @@
<a href="https://coveralls.io/github/WenjieDu/PyPOTS">
<img alt="Coveralls coverage" src="https://img.shields.io/coverallsCoverage/github/WenjieDu/PyPOTS?branch=main&logo=coveralls&color=00e09e&label=Coverage">
</a>
<a href="https://anaconda.org/conda-forge/pypots">
<img alt="Conda downloads" src="https://img.shields.io/conda/dn/conda-forge/pypots?label=Conda%20Downloads&color=48c0a3">
</a>
<a href="https://pypi.org/project/pypots">
<img alt="PyPI downloads" src="https://static.pepy.tech/personalized-badge/pypots?period=total&units=international_system&left_color=grey&right_color=teal&left_text=PyPI%20Downloads">
</a>
<a href="https://github.com/WenjieDu/PyPOTS/actions/workflows/testing.yml">
<img alt="GitHub Testing" src="https://github.com/WenjieDu/PyPOTS/actions/workflows/testing.yml/badge.svg">
<img alt="GitHub Testing" src="https://img.shields.io/github/actions/workflow/status/wenjiedu/pypots/testing.yml?logo=github&color=48c0a3&label=CI">
</a>
<a href="https://doi.org/10.5281/zenodo.6823221">
<img alt="Zenodo DOI" src="https://zenodo.org/badge/DOI/10.5281/zenodo.6823221.svg">
<img alt="Zenodo DOI" src="https://img.shields.io/badge/DOI-10.5281/zenodo.6823221-21a675">
</a>
<a href="https://anaconda.org/conda-forge/pypots">
<img alt="Conda downloads" src="https://img.shields.io/conda/dn/conda-forge/pypots?label=Conda%20Downloads&color=057748&logo=anaconda&logoColor=white">
</a>
<a href="https://pypi.org/project/pypots">
<img alt="PyPI downloads" src="https://static.pepy.tech/personalized-badge/pypots?period=total&units=international_system&left_color=grey&right_color=teal&left_text=PyPI%20Downloads&logo=github">
</a>

</p>

⦿ `Motivation`: Due to all kinds of reasons like failure of collection sensors, communication error, and unexpected malfunction, missing values are common to see in time series from the real-world environment. This makes partially-observed time series (POTS) a pervasive problem in open-world modeling and prevents advanced data analysis. Although this problem is important, the area of data mining on POTS still lacks a dedicated toolkit. PyPOTS is created to fill in this blank.
Expand All @@ -54,6 +55,7 @@ To make various open-source time-series datasets readily available to our users,
Visit [TSDB](https://github.com/WenjieDu/TSDB) right now to know more about this handy tool 🛠! It now supports a total of 119 open-source datasets.
<br clear="left">


## ❖ Installation
PyPOTS now is available on <a href="https://anaconda.org/conda-forge/pypots"><img alt="on Anaconda" align="center"
src="https://img.shields.io/badge/Anaconda--lightgreen?style=social&logo=anaconda"></a>❗️
Expand All @@ -66,8 +68,17 @@ Install the latest release from PyPI:
or install from the source code with the latest features not officially released in a version:
> pip install https://github.com/WenjieDu/PyPOTS/archive/main.zip

<details open>
<summary><b>Below is an example applying SAITS in PyPOTS to impute missing values in the dataset PhysioNet2012:</b></summary>

## ❖ Usage
PyPOTS tutorials have been released. You can find them [here](https://github.com/WenjieDu/PyPOTS/tree/main/tutorials).
If you have further questions, please refer to PyPOTS documentation [📑http:https://pypots.readthedocs.io](http:https://pypots.readthedocs.io).
Besides, you can also
[raise an issue](https://github.com/WenjieDu/PyPOTS/issues) or
[ask in our community](https://join.slack.com/t/pypots-dev/shared_invite/zt-1gq6ufwsi-p0OZdW~e9UW_IA4_f1OfxA).
And please allow us to present you a usage example of imputing missing values in time series with PyPOTS below.

<details>
<summary><b>Click here to see an example applying SAITS on PhysioNet2012 for imputation:</b></summary>

``` python
import numpy as np
Expand All @@ -93,6 +104,7 @@ mae = cal_mae(imputation, X_intact, indicating_mask) # calculate mean absolute
```
</details>


## ❖ Available Algorithms
PyPOTS supports imputation, classification, clustering, and forecasting tasks on multivariate time series with missing values. The currently available algorithms of four tasks are cataloged in the following table with four partitions. The paper references are all listed at the bottom of this readme file. Please refer to them if you want more details.

Expand Down Expand Up @@ -160,8 +172,6 @@ Your star is your recognition to PyPOTS, and it matters!


## ❖ Attention 👀
The documentation and tutorials are under construction.

‼️ PyPOTS is currently under developing. If you like it and look forward to its growth, <ins>please give PyPOTS a star
and watch it to keep you posted on its progress and to let me know that its development is meaningful</ins>. If you have
any feedback, or want to contribute ideas/suggestions or share time-series related algorithms/papers, please join PyPOTS
Expand Down
File renamed without changes.
9 changes: 5 additions & 4 deletions pypots/utils/commands/base.py → pypots/cli/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@ def check_if_under_root_dir(strict: bool = True):
)

if strict:
assert check_result, RuntimeError(
"Command `pypots-cli dev` can only be run under the root directory of project PyPOTS, "
f"but you're running it under the path {os.getcwd()}. Please make a check."
)
if not check_result:
raise RuntimeError(
"Command `pypots-cli dev` can only be run under the root directory of project PyPOTS, "
f"but you're running it under the path {os.getcwd()}. Please make a check."
)

return check_result

Expand Down
4 changes: 2 additions & 2 deletions pypots/utils/commands/dev.py → pypots/cli/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import shutil
from argparse import Namespace

from pypots.utils.commands.base import BaseCommand
from pypots.cli.base import BaseCommand
from pypots.utils.logging import logger

IMPORT_ERROR_MESSAGE = (
Expand Down Expand Up @@ -116,7 +116,7 @@ def __init__(

def checkup(self):
"""Run some checks on the arguments to avoid error usages"""
self.check_if_under_root_dir()
self.check_if_under_root_dir(strict=True)

if self._k is not None:
assert self._run_tests, (
Expand Down
8 changes: 5 additions & 3 deletions pypots/utils/commands/doc.py → pypots/cli/doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from tsdb.data_processing import _download_and_extract

from pypots.utils.commands.base import BaseCommand
from pypots.cli.base import BaseCommand
from pypots.utils.logging import logger

CLONED_LATEST_PYPOTS = "temp_pypots_latest"
Expand Down Expand Up @@ -145,7 +145,7 @@ def __init__(

def checkup(self):
"""Run some checks on the arguments to avoid error usages"""
self.check_if_under_root_dir()
self.check_if_under_root_dir(strict=True)

if self._cleanup:
assert not self._gene_rst and not self._gene_html and not self._view_doc, (
Expand Down Expand Up @@ -191,8 +191,10 @@ def run(self):

# Generate the docs according to the cloned code
logger.info("Generating rst files...")
os.environ[
"SPHINX_APIDOC_OPTIONS"
] = "members,undoc-members,show-inheritance,inherited-members"
self.execute_command(
"SPHINX_APIDOC_OPTIONS=members,undoc-members,show-inheritance,inherited-members "
f"sphinx-apidoc {CLONED_LATEST_PYPOTS} -o {CLONED_LATEST_PYPOTS}/rst"
)

Expand Down
29 changes: 17 additions & 12 deletions pypots/utils/commands/env.py → pypots/cli/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

from setuptools.config import read_configuration

from pypots.utils.commands.base import BaseCommand
from pypots.cli.base import BaseCommand
from pypots.utils.logging import logger


Expand Down Expand Up @@ -90,7 +90,7 @@ def __init__(

def checkup(self):
"""Run some checks on the arguments to avoid error usages"""
self.check_if_under_root_dir()
self.check_if_under_root_dir(strict=True)

def run(self):
"""Execute the given command."""
Expand All @@ -112,23 +112,28 @@ def run(self):
"conda install pyg pytorch-scatter pytorch-sparse -c pyg"
)

dependencies = ""
for i in setup_cfg["options"]["extras_require"][self._install]:
dependencies += f"'{i}' "
if self._install != "optional":
dependencies = ""
for i in setup_cfg["options"]["extras_require"][self._install]:
dependencies += f"'{i}' "

if "torch-geometric" in dependencies:
dependencies = dependencies.replace("'torch-geometric'", "")
dependencies = dependencies.replace("'torch-scatter'", "")
dependencies = dependencies.replace("'torch-sparse'", "")
if "torch-geometric" in dependencies:
dependencies = dependencies.replace("'torch-geometric'", "")
dependencies = dependencies.replace("'torch-scatter'", "")
dependencies = dependencies.replace("'torch-sparse'", "")

conda_comm = f"conda install {dependencies} -c conda-forge"
self.execute_command(conda_comm)
conda_comm = f"conda install {dependencies} -c conda-forge"
self.execute_command(conda_comm)

else: # self._tool == "pip"
torch_version = torch.__version__

if not (torch.cuda.is_available() and torch.cuda.device_count() > 0):
if "cpu" not in torch_version:
torch_version = torch_version + "+cpu"

self.execute_command(
f"pip install -e '.[optional]' -f 'https://data.pyg.org/whl/torch-{torch_version}.html'"
f"python -m pip install -e '.[optional]' -f https://data.pyg.org/whl/torch-{torch_version}.html"
)

if self._install != "optional":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

from argparse import ArgumentParser

from pypots.utils.commands.dev import DevCommand
from pypots.utils.commands.doc import DocCommand
from pypots.utils.commands.env import EnvCommand
from pypots.cli.dev import DevCommand
from pypots.cli.doc import DocCommand
from pypots.cli.env import EnvCommand


def main():
Expand Down
23 changes: 19 additions & 4 deletions pypots/tests/environment_for_conda_test.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
name: pypots-test

channels:
- conda-forge
- pytorch
- pyg
- nodefaults

dependencies:
# basic
- conda-forge::python
- conda-forge::pip
- conda-forge::scipy
Expand All @@ -13,12 +16,24 @@ dependencies:
- conda-forge::pandas <2.0.0
- conda-forge::h5py
- conda-forge::tensorboard
- conda-forge::pytest-cov
- conda-forge::pytest-xdist
- conda-forge::coverage
- conda-forge::pycorruptor
- conda-forge::tsdb
- pytorch::pytorch >=1.10.0

# optional
- pyg::pyg
- pyg::pytorch-scatter
- pyg::pytorch-sparse
- pyg::pytorch-sparse

# test
- conda-forge::pytest-cov
- conda-forge::pytest-xdist

# doc
- conda-forge::sphinx
- conda-forge::sphinxcontrib-bibtex
- conda-forge::furo

# dev
- conda-forge::black
- conda-forge::flake8
Loading