• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

WenjieDu / PyPOTS / 4755049409

pending completion
4755049409

push

github

GitHub
Merge pull request #63 from WenjieDu/dev

61 of 61 new or added lines in 5 files covered. (100.0%)

2832 of 3490 relevant lines covered (81.15%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pypots/utils/commands/doc.py
1
"""
2
CLI tools to help the development team build PyPOTS.
3
"""
4

5
# Created by Wenjie Du <wenjay.du@gmail.com>
6
# License: GLP-v3
7

8
import os
×
9
import shutil
×
10
from argparse import ArgumentParser, Namespace
×
11

12
from pypots.utils.commands.base import BaseCommand
×
13
from pypots.utils.logging import logger
×
14
from tsdb.data_processing import _download_and_extract
×
15

16
CLONED_LATEST_PYPOTS = "temp_pypots_latest"
×
17

18
# These files need to be updated while generating the new documentation
19
DOC_RST_FILES = [
×
20
    "pypots.rst",
21
    "pypots.imputation.rst",
22
    "pypots.classification.rst",
23
    "pypots.clustering.rst",
24
    "pypots.forecasting.rst",
25
    "pypots.data.rst",
26
    "pypots.utils.rst",
27
]
28

29
IMPORT_ERROR_MESSAGE = (
×
30
    "`pypots-cli doc` command is for PyPOTS developers to build documentation easily. "
31
    "Therefore, you need a complete PyPOTS development environment. However, you are missing some dependencies. "
32
    "Please refer to https://github.com/WenjieDu/PyPOTS/blob/main/environment-dev.yml for dependency details. "
33
)
34

35

36
def doc_command_factory(args: Namespace):
×
37
    return DocCommand(
×
38
        args.gene_rst,
39
        args.branch,
40
        args.gene_html,
41
        args.view_doc,
42
        args.port,
43
        args.cleanup,
44
    )
45

46

47
def purge_temp_files():
×
48
    logger.info(
×
49
        f"Directories _build and {CLONED_LATEST_PYPOTS} will be deleted if exist"
50
    )
51
    shutil.rmtree("docs/_build", ignore_errors=True)
×
52
    shutil.rmtree(CLONED_LATEST_PYPOTS, ignore_errors=True)
×
53

54

55
class DocCommand(BaseCommand):
×
56
    """CLI tools helping build PyPOTS documentation.
57

58
    Notes
59
    -----
60
    Only code pushed to GitHub can be used for documentation generation.
61
    During generation, PyPOTS repo on GitHub will firstly be cloned to local with the branch specified by
62
    argument `--branch`. The generated rst files will replace the old ones directly. To view the updated
63
    documentation, use option `--view_doc` to generate the doc into HTMLs and deploy it locally for view.
64
    After running `--view_doc`, the generated static files won't be deleted automatically. To purge them,
65
    run the command with option `--cleanup`.
66

67
    Examples
68
    --------
69
    $ pypots-cli doc --gene_rst [--branch main]
70
    $ pypots-cli doc --view_doc [--port 9075]
71
    $ pypots-cli doc --cleanup
72

73
    """
74

75
    @staticmethod
×
76
    def register_subcommand(parser: ArgumentParser):
×
77
        sub_parser = parser.add_parser(
×
78
            "doc", help="CLI tools helping build PyPOTS documentation"
79
        )
80

81
        sub_parser.add_argument(
×
82
            "--gene_rst",
83
            dest="gene_rst",
84
            action="store_true",
85
            help="Generate rst (reStructuredText) documentation according to the latest code on Github",
86
        )
87
        sub_parser.add_argument(
×
88
            "--branch",
89
            type=str,
90
            default="main",
91
            choices=["main", "dev"],
92
            help="Code on which branch will be used for documentation generating",
93
        )
94
        sub_parser.add_argument(
×
95
            "--gene_html",
96
            dest="gene_html",
97
            action="store_true",
98
            help="Generate the sphinx documentation into static HTML files",
99
        )
100
        sub_parser.add_argument(
×
101
            "--view_doc",
102
            dest="view_doc",
103
            action="store_true",
104
            help="Deploy the generated HTML documentation locally for view",
105
        )
106
        sub_parser.add_argument(
×
107
            "--port",
108
            type=int,
109
            default=9075,
110
            help="Use which port to deploy the web server for doc view",  # 9075 looks like "POTS", so use it as default
111
        )
112
        sub_parser.add_argument(
×
113
            "--cleanup",
114
            dest="cleanup",
115
            action="store_true",
116
            help="Delete all caches and static resources like HTML and CSS files ",
117
        )
118

119
        sub_parser.set_defaults(func=doc_command_factory)
×
120

121
    def __init__(
×
122
        self,
123
        gene_rst: bool,
124
        branch: str,
125
        gene_html: bool,
126
        view_doc: bool,
127
        port: int,
128
        cleanup: bool,
129
    ):
130
        self._gene_rst = gene_rst
×
131
        self._branch = branch
×
132
        self._gene_html = gene_html
×
133
        self._view_doc = view_doc
×
134
        self._port = port
×
135
        self._cleanup = cleanup
×
136

137
    def check_arguments(self):
×
138
        """Run some checks on the arguments to avoid error usages"""
139
        self.check_if_under_root_dir()
×
140

141
        if self._cleanup:
×
142
            assert not self._gene_rst and not self._gene_html and not self._view_doc, (
×
143
                "Argument `--cleanup` should be used alone. "
144
                "Try `pypots-cli doc --cleanup`"
145
            )
146

147
    def run(self):
×
148
        """Execute the given command."""
149

150
        # check arguments first
151
        self.check_arguments()
×
152

153
        try:
×
154
            if self._cleanup:
×
155
                logger.info("Purging static files...")
×
156
                purge_temp_files()
×
157
                logger.info("Purging finished successfully.")
×
158

159
            if self._gene_rst:
×
160
                if os.path.exists(CLONED_LATEST_PYPOTS):
×
161
                    logger.info(
×
162
                        f"Directory {CLONED_LATEST_PYPOTS} exists, deleting it..."
163
                    )
164
                    shutil.rmtree(CLONED_LATEST_PYPOTS, ignore_errors=True)
×
165

166
                # Download the latest code from GitHub
167
                logger.info(
×
168
                    f"Downloading PyPOTS with the latest code on branch '{self._branch}' "
169
                    f"from GitHub into {CLONED_LATEST_PYPOTS}..."
170
                )
171
                url = f"https://github.com/WenjieDu/PyPOTS/archive/refs/heads/{self._branch}.zip"
×
172
                _download_and_extract(url=url, saving_path=CLONED_LATEST_PYPOTS)
×
173

174
                code_dir = f"{CLONED_LATEST_PYPOTS}/PyPOTS-{self._branch}"
×
175
                files_to_move = os.listdir(code_dir)
×
176
                destination_dir = os.path.join(os.getcwd(), CLONED_LATEST_PYPOTS)
×
177
                for f_ in files_to_move:
×
178
                    shutil.move(os.path.join(code_dir, f_), destination_dir)
×
179
                # delete code in tests because we don't need its doc
180
                shutil.rmtree(
×
181
                    f"{CLONED_LATEST_PYPOTS}/pypots/tests", ignore_errors=True
182
                )
183

184
                # Generate the docs according to the cloned code
185
                logger.info("Generating rst files...")
×
186
                self.execute_command(
×
187
                    "SPHINX_APIDOC_OPTIONS=members,undoc-members,show-inheritance,inherited-members "
188
                    f"sphinx-apidoc {CLONED_LATEST_PYPOTS} -o {CLONED_LATEST_PYPOTS}/rst"
189
                )
190

191
                # Only save the files we need.
192
                logger.info("Updating the old documentation...")
×
193
                for f_ in DOC_RST_FILES:
×
194
                    file_to_copy = f"{CLONED_LATEST_PYPOTS}/rst/{f_}"
×
195
                    shutil.copy(file_to_copy, "docs")
×
196

197
                # Delete the useless files.
198
                shutil.rmtree(f"{CLONED_LATEST_PYPOTS}", ignore_errors=True)
×
199

200
            if self._gene_html:
×
201
                logger.info("Generating static HTML files...")
×
202
                purge_temp_files()
×
203
                self.execute_command("cd docs && make html")
×
204

205
            if self._view_doc:
×
206
                assert os.path.exists(
×
207
                    "docs/_build/html"
208
                ), "docs/_build/html does not exists, please run `pypots-cli doc --gene_html` first"
209
                logger.info(f"Deploying HTML to http://127.0.0.1:{self._port}...")
×
210
                self.execute_command(
×
211
                    f"python -m http.server {self._port} -d docs/_build/html -b 127.0.0.1"
212
                )
213

214
        except ImportError:
×
215
            raise ImportError(IMPORT_ERROR_MESSAGE)
×
216
        except Exception as e:
×
217
            raise RuntimeError(e)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc