Skip to content

Commit 193f1a4

Browse files
authored
Merge pull request #326 from CycloneDX/callable-module
feat: make package/module callable
2 parents b647219 + 2bac83a commit 193f1a4

File tree

5 files changed

+94
-7
lines changed

5 files changed

+94
-7
lines changed

cyclonedx_py/__main__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# encoding: utf-8
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
# Copyright (c) OWASP Foundation. All Rights Reserved.
17+
18+
from .client import main
19+
20+
main(prog_name=__package__)

cyclonedx_py/client.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import os
2323
import sys
2424
from datetime import datetime
25+
from typing import Optional
2526

2627
from cyclonedx.model import Tool
2728
from cyclonedx.model.bom import Bom
@@ -122,8 +123,8 @@ def execute(self) -> None:
122123
output.output_to_file(filename=output_filename, allow_overwrite=self._arguments.output_file_overwrite)
123124

124125
@staticmethod
125-
def get_arg_parser() -> argparse.ArgumentParser:
126-
arg_parser = argparse.ArgumentParser(description='CycloneDX SBOM Generator')
126+
def get_arg_parser(*, prog: Optional[str] = None) -> argparse.ArgumentParser:
127+
arg_parser = argparse.ArgumentParser(prog=prog, description='CycloneDX SBOM Generator')
127128

128129
input_group = arg_parser.add_mutually_exclusive_group(required=True)
129130
input_group.add_argument(
@@ -254,8 +255,8 @@ def _get_input_parser(self) -> BaseParser:
254255
raise CycloneDxCmdException('Parser type could not be determined.')
255256

256257

257-
def main() -> None:
258-
parser = CycloneDxCmd.get_arg_parser()
258+
def main(*, prog_name: Optional[str] = None) -> None:
259+
parser = CycloneDxCmd.get_arg_parser(prog=prog_name)
259260
args = parser.parse_args()
260261
CycloneDxCmd(args).execute()
261262

docs/usage.rst

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@ Usage
44
Command Line Usage
55
------------------
66

7-
Once installed, you can access the full documentation by running ``--help``:
7+
Once installed, you can call the tool via the following methods:
8+
9+
.. code-block:: bash
10+
11+
$ python3 -m cyclonedx_py
12+
$ cyclonedx-py
13+
$ cyclonedx-bom
14+
15+
The full documentation can be issued by running with ``--help``:
816

917
.. code-block:: bash
1018
@@ -215,8 +223,8 @@ Requirements
215223
216224
* :py:mod:`cyclonedx_py.parser.requirements.RequirementsParser`: Parses a multiline string that you provide that conforms
217225
to the ``requirements.txt`` :pep:`508` standard.
218-
* :py:mod:`cyclonedx_py.parser.requirements.RequirementsFileParser`: Parses a file that you provide the path to that conforms to the ``requirements.txt`` :pep:`508` standard. It supports nested
219-
files, so if there is a line in your ``requirements.txt`` file with the ``-r requirements-nested.txt`` syntax, it'll parse the nested file as part of the same file.
226+
* :py:mod:`cyclonedx_py.parser.requirements.RequirementsFileParser`: Parses a file that you provide the path to that conforms to the ``requirements.txt`` :pep:`508` standard.
227+
It supports nested files, so if there is a line in your ``requirements.txt`` file with the ``-r requirements-nested.txt`` syntax, it'll parse the nested file as part of the same file.
220228
221229
CycloneDX software bill-of-materials require pinned versions of requirements. If your `requirements.txt` does not have
222230
pinned versions, warnings will be recorded and the dependencies without pinned versions will be excluded from the

tests/integration/__init__.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# encoding: utf-8
2+
3+
# This file is part of CycloneDX Python Lib
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
# SPDX-License-Identifier: Apache-2.0
18+
# Copyright (c) OWASP Foundation. All Rights Reserved.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# encoding: utf-8
2+
3+
# This file is part of CycloneDX Python Lib
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
# SPDX-License-Identifier: Apache-2.0
18+
# Copyright (c) OWASP Foundation. All Rights Reserved.
19+
20+
import subprocess
21+
import sys
22+
from unittest import TestCase
23+
24+
import cyclonedx_py
25+
26+
27+
class TestCli(TestCase):
28+
29+
def test_callable_as_module(self) -> None:
30+
args = [sys.executable, '-m', cyclonedx_py.__name__, '--help']
31+
32+
# Test whether the call passed, is fair enough for now.
33+
# Additional tests may come later, to check output etc.
34+
returncode = subprocess.call(
35+
args,
36+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
37+
shell=False,
38+
)
39+
40+
self.assertEqual(0, returncode, msg='subprocess returned unexpected non-zero')

0 commit comments

Comments
 (0)