pax_global_header00006660000000000000000000000064147327111200014510gustar00rootroot0000000000000052 comment=4a2f6e277a64e8d76c63eedb5866cc604568d835 jeanralphaviles-comment_parser-4a2f6e2/000077500000000000000000000000001473271112000203075ustar00rootroot00000000000000jeanralphaviles-comment_parser-4a2f6e2/.github/000077500000000000000000000000001473271112000216475ustar00rootroot00000000000000jeanralphaviles-comment_parser-4a2f6e2/.github/workflows/000077500000000000000000000000001473271112000237045ustar00rootroot00000000000000jeanralphaviles-comment_parser-4a2f6e2/.github/workflows/deploy.yml000066400000000000000000000017251473271112000257300ustar00rootroot00000000000000name: Deploy on: release: types: [published] workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Dependencies run: pip install -r requirements.txt - name: Build run: python setup.py sdist - name: Upload Distributions uses: actions/upload-artifact@v4 with: name: release-dists path: dist/ deploy: runs-on: ubuntu-latest needs: - build environment: name: pypi url: https://pypi.org/p/comment-parser permissions: id-token: write steps: - name: Retrieve Distributions uses: actions/download-artifact@v4 with: name: release-dists path: dist/ - name: Publish release distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: dist/ print-hash: true skip-existing: true jeanralphaviles-comment_parser-4a2f6e2/.github/workflows/test.yml000066400000000000000000000013171473271112000254100ustar00rootroot00000000000000name: Run Tests on: push: jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: 3.x - name: Install Dependencies run: pip install -r requirements.txt -r requirements-dev.txt - name: Type Checking run: python -m pytype --jobs auto - name: Test run: python -m pytest - name: Lint run: python -m pylint comment_parser - name: Formatting run: python -m yapf -drp comment_parser build: runs-on: ubuntu-latest needs: - test steps: - uses: actions/checkout@v4 - name: Build run: python setup.py sdist jeanralphaviles-comment_parser-4a2f6e2/.gitignore000066400000000000000000000013341473271112000223000ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *,cover # Translations *.mo *.pot # Django stuff: *.log # Sphinx documentation docs/_build/ # PyBuilder target/ # pytype .pytype/ jeanralphaviles-comment_parser-4a2f6e2/.pylintrc000066400000000000000000000001261473271112000221530ustar00rootroot00000000000000[MASTER] disable= duplicate-code, too-many-branches, too-many-statements, jeanralphaviles-comment_parser-4a2f6e2/LICENSE000066400000000000000000000020751473271112000213200ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Jean-Ralph Aviles Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. jeanralphaviles-comment_parser-4a2f6e2/MANIFEST.in000066400000000000000000000000421473271112000220410ustar00rootroot00000000000000include README.md include LICENSE jeanralphaviles-comment_parser-4a2f6e2/README.md000066400000000000000000000104751473271112000215750ustar00rootroot00000000000000# Comment Parser [![Run Tests](https://github.com/jeanralphaviles/comment_parser/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/jeanralphaviles/comment_parser/actions/workflows/test.yml) [![PyPI status](https://img.shields.io/pypi/status/comment_parser.svg)](https://pypi.python.org/pypi/comment_parser/) [![PyPI version shields.io](https://img.shields.io/pypi/v/comment_parser.svg)](https://pypi.python.org/pypi/comment_parser/) [![PyPI license](https://img.shields.io/pypi/l/comment_parser.svg)](https://pypi.python.org/pypi/comment_parser/) [![PyPI pyversions](https://img.shields.io/pypi/pyversions/comment_parser.svg)](https://pypi.python.org/pypi/comment_parser/) Python module used to extract comments from source code files of various types. ## Installation ### Prerequisites * libmagic ### Linux/Unix ```shell sudo pip3 install comment_parser ``` ### OSX and Windows Additionally, complete the special installation requirements for [python-magic](https://github.com/ahupp/python-magic). ## Usage To use, simply run: ```python >>> from comment_parser import comment_parser >>> # Returns a list of comment_parser.parsers.common.Comments >>> comment_parser.extract_comments('/path/to/source_file') >>> # Or >>> comment_parser.extract_comments_from_str('...') ``` ### extract_comments signatures ```python def extract_comments(filename, mime=None): """Extracts and returns the comments from the given source file. Args: filename: String name of the file to extract comments from. mime: Optional MIME type for file (str). Note some MIME types accepted don't comply with RFC2045. If not given, an attempt to deduce the MIME type will occur. Returns: Python list of parsers.common.Comment in the order that they appear in the source file. Raises: UnsupportedError: If filename is of an unsupported MIME type. """ pass def extract_comments_from_str(code, mime=None): """Extracts and returns comments from the given source string. Args: code: String containing code to extract comments from. mime: Optional MIME type for code (str). Note some MIME types accepted don't comply with RFC2045. If not given, an attempt to deduce the MIME type will occur. Returns: Python list of parsers.common.Comment in the order that they appear in the source code. Raises: UnsupportedError: If code is of an unsupported MIME type. """ pass ``` ### Comments Interface ```python class Comment(object): """Represents comments found in source files.""" def text(self): """Returns the comment's text. Returns: String """ pass def line_number(self): """Returns the line number the comment was found on. Returns: Int """ pass def is_multiline(self): """Returns whether this comment was a multiline comment. Returns: True if comment was a multiline comment, False if not. """ pass def __str__(self): pass def __eq__(self, other): pass ``` ## Development ### Install Dependencies ```shell pip install -r requirements.txt -r requirements-dev.txt ``` ### Running locally Start python in the base of repository. ```python from comment_parser import comment_parser comment_parser.extract_comments('foo.c', mime='text/x-c') ``` ### Running tests ```shell python -m pytest ``` ### Running pylint ```shell pylint comment_parser ``` ### Running formatter ```shell yapf -rip . ``` ### Deploying to PyPi ```shell python setup.py sdist twine upload dist/* ``` ## Supported Programming Languages | Language | Mime String | |------------ |------------------------- | | C | text/x-c | | C++/C# | text/x-c++ | | Go | text/x-go | | HTML | text/html | | Java | text/x-java-source | | Javascript | application/javascript | | Python | text/x-python | | Python | text/x-script.python | | Ruby | text/x-ruby | | Shell | text/x-shellscript | | XML | text/xml | And more to come! *Check comment_parser.py for corresponding MIME types.* jeanralphaviles-comment_parser-4a2f6e2/comment_parser/000077500000000000000000000000001473271112000233255ustar00rootroot00000000000000jeanralphaviles-comment_parser-4a2f6e2/comment_parser/__init__.py000066400000000000000000000000001473271112000254240ustar00rootroot00000000000000jeanralphaviles-comment_parser-4a2f6e2/comment_parser/comment_parser.py000077500000000000000000000074011473271112000267220ustar00rootroot00000000000000#!/usr/bin/python """This program parses various source files and extracts the comment texts. Currently supported languages: Bash/sh C C++ Go HTML Java Javascript Ruby XML Dependencies: python-magic: pip install python-magic (optional) """ import sys from typing import List, Optional try: import magic HAS_MAGIC = True except ImportError: HAS_MAGIC = False from comment_parser.parsers import c_parser from comment_parser.parsers import common from comment_parser.parsers import go_parser from comment_parser.parsers import html_parser from comment_parser.parsers import js_parser from comment_parser.parsers import python_parser from comment_parser.parsers import ruby_parser from comment_parser.parsers import shell_parser MIME_MAP = { 'application/javascript': js_parser, # Javascript 'text/html': html_parser, # HTML 'text/x-c': c_parser, # C 'text/x-c++': c_parser, # C++/C# 'text/x-go': go_parser, # Go 'text/x-java': c_parser, # Java 'text/x-java-source': c_parser, # Java 'text/x-javascript': js_parser, # Javascript 'text/x-python': python_parser, # Python 'text/x-ruby': ruby_parser, # Ruby 'text/x-script.python': python_parser, # Python 'text/x-shellscript': shell_parser, # Unix shell 'text/xml': html_parser, # XML } class Error(Exception): """Base Error class in this module.""" class UnsupportedError(Error): """Raised when trying to extract comments from an unsupported MIME type.""" class ParseError(Error): """Raised when a parser issue is encountered.""" def extract_comments(filename: str, mime: Optional[str] = None) -> List[common.Comment]: """Extracts and returns the comments from the given source file. Args: filename: String name of the file to extract comments from. mime: Optional MIME type for file (str). Note some MIME types accepted don't comply with RFC2045. If not given, an attempt to deduce the MIME type will occur. Returns: Python list of parsers.common.Comment in the order that they appear in the source file. Raises: UnsupportedError: If filename is of an unsupported MIME type. """ with open(filename, 'r', encoding='utf-8') as code: return extract_comments_from_str(code.read(), mime) def extract_comments_from_str(code: str, mime: Optional[str] = None ) -> List[common.Comment]: """Extracts and returns comments from the given source string. Args: code: String containing code to extract comments from. mime: Optional MIME type for code (str). Note some MIME types accepted don't comply with RFC2045. If not given, an attempt to deduce the MIME type will occur. Returns: Python list of parsers.common.Comment in the order that they appear in the source code. Raises: UnsupportedError: If code is of an unsupported MIME type. """ if not mime: if not HAS_MAGIC: raise ImportError('python-magic was not imported') mime = magic.from_buffer(code, mime=True) if isinstance(mime, bytes): mime = mime.decode('utf-8') if mime not in MIME_MAP: raise UnsupportedError(f'Unsupported MIME type {mime}') try: parser = MIME_MAP[mime] return parser.extract_comments(code) except common.Error as e: raise ParseError() from e def main(argv): """Extracts comments from files and prints them to stdout.""" for filename in argv: try: comments = extract_comments(filename) for comment in comments: print(comment.text()) except Error as exception: sys.stderr.write(str(exception)) if __name__ == '__main__': main(sys.argv[1:]) jeanralphaviles-comment_parser-4a2f6e2/comment_parser/parsers/000077500000000000000000000000001473271112000250045ustar00rootroot00000000000000jeanralphaviles-comment_parser-4a2f6e2/comment_parser/parsers/__init__.py000066400000000000000000000000001473271112000271030ustar00rootroot00000000000000jeanralphaviles-comment_parser-4a2f6e2/comment_parser/parsers/c_parser.py000066400000000000000000000044131473271112000271560ustar00rootroot00000000000000#!/usr/bin/python """This module provides methods for parsing comments from C family languages. Works with: C99+ C++ Objective-C Java """ import re from bisect import bisect_left from typing import List from comment_parser.parsers import common def extract_comments(code: str) -> List[common.Comment]: """Extracts a list of comments from the given C family source code. Comments are represented with the Comment class found in the common module. C family comments come in two forms, single and multi-line comments. - Single-line comments begin with '//' and continue to the end of line. - Multi-line comments begin with '/*' and end with '*/' and can span multiple lines of code. If a multi-line comment does not terminate before EOF is reached, then an exception is raised. Note that this doesn't take language-specific preprocessor directives into consideration. Args: code: String containing code to extract comments from. Returns: Python list of common.Comment in the order that they appear in the code. Raises: common.UnterminatedCommentError: Encountered an unterminated multi-line comment. """ pattern = r""" (?P (\"([^\"\n])*\")+) | (?P //(?P.*)?$) | (?P /\*(?P(.|\n)*?)?\*/) | (?P /\*(.*)?) """ compiled = re.compile(pattern, re.VERBOSE | re.MULTILINE) lines_indexes = [] for match in re.finditer(r"$", code, re.M): lines_indexes.append(match.start()) comments = [] for match in compiled.finditer(code): kind = match.lastgroup start_character = match.start() line_no = bisect_left(lines_indexes, start_character) if kind == "single": comment_content = match.group("single_content") comment = common.Comment(comment_content, line_no + 1) comments.append(comment) elif kind == "multi": comment_content = match.group("multi_content") comment = common.Comment(comment_content, line_no + 1, multiline=True) comments.append(comment) elif kind == "error": raise common.UnterminatedCommentError() return comments jeanralphaviles-comment_parser-4a2f6e2/comment_parser/parsers/common.py000066400000000000000000000032401473271112000266450ustar00rootroot00000000000000#!/usr/bin/python """This module provides constructs common to all comment parsers.""" class Error(Exception): """Base Error class for all comment parsers.""" class FileError(Error): """Raised if there is an issue reading a given file.""" class UnterminatedCommentError(Error): """Raised if an Unterminated multi-line comment is encountered.""" class Comment(): """Represents comments found in source files.""" def __init__(self, text: str, line_number: int, multiline: bool = False): """Initializes Comment. Args: text: String text of comment. line_number: Line number (int) comment was found on. multiline: Boolean whether this comment was a multiline comment. """ self._text = text self._line_number = line_number self._multiline = multiline def text(self) -> str: """Returns the comment's text. Returns: String """ return self._text def line_number(self) -> int: """Returns the line number the comment was found on. Returns: Int """ return self._line_number def is_multiline(self) -> bool: """Returns whether this comment was a multiline comment. Returns: True if comment was a multiline comment, False if not. """ return self._multiline def __str__(self) -> str: return self._text def __repr__(self) -> str: return f'Comment({self._text}, {self._line_number}, {self._multiline})' def __eq__(self, other: object) -> bool: if isinstance(other, self.__class__): if self.__dict__ == other.__dict__: return True return False jeanralphaviles-comment_parser-4a2f6e2/comment_parser/parsers/go_parser.py000066400000000000000000000073111473271112000273410ustar00rootroot00000000000000#!/usr/bin/python """This module provides methods for parsing comments from Go source code.""" from typing import List from comment_parser.parsers import common def extract_comments(code: str) -> List[common.Comment]: """Extracts a list of comments from the given Go source code. Comments are represented with the Comment class found in the common module. Go comments come in two forms, single and multi-line comments. - Single-line comments begin with '//' and continue to the end of line. - Multi-line comments begin with '/*' and end with '*/' and can span multiple lines of code. If a multi-line comment does not terminate before EOF is reached, then an exception is raised. Go comments are not allowed to start in a string or rune literal. This module makes sure to watch out for those. https://golang.org/ref/spec#Comments Args: code: String containing code to extract comments from. Returns: Python list of common.Comment in the order that they appear in the code. Raises: common.UnterminatedCommentError: Encountered an unterminated multi-line comment. """ state = 0 current_comment = '' comments = [] line_counter = 1 comment_start = 1 string_char = '' for char in code: if state == 0: # Waiting for comment start character or beginning of # string or rune literal. if char == '/': state = 1 elif char in ('"', "'", '`'): string_char = char state = 5 elif state == 1: # Found comment start character, classify next character and # determine if single or multi-line comment. if char == '/': state = 2 elif char == '*': comment_start = line_counter state = 3 else: state = 0 elif state == 2: # In single-line comment, read characters util EOL. if char == '\n': comment = common.Comment(current_comment, line_counter) comments.append(comment) current_comment = '' state = 0 else: current_comment += char elif state == 3: # In multi-line comment, add characters until '*' is # encountered. if char == '*': state = 4 else: current_comment += char elif state == 4: # In multi-line comment with asterisk found. Determine if # comment is ending. if char == '/': comment = common.Comment(current_comment, comment_start, multiline=True) comments.append(comment) current_comment = '' state = 0 else: current_comment += '*' # Care for multiple '*' in a row if char != '*': current_comment += char state = 3 elif state == 5: # In string literal, expect literal end or escape character. if char == string_char: state = 0 elif char == '\\': state = 6 elif state == 6: # In string literal, escaping current char. state = 5 if char == '\n': line_counter += 1 # EOF. if state in (3, 4): raise common.UnterminatedCommentError() if state == 2: # Was in single-line comment. Create comment. comment = common.Comment(current_comment, line_counter) comments.append(comment) return comments jeanralphaviles-comment_parser-4a2f6e2/comment_parser/parsers/html_parser.py000066400000000000000000000036771473271112000277130ustar00rootroot00000000000000#!/usr/bin/python """This module provides methods for parsing comments from HTML family languages. Works with: HTML XML """ import re from bisect import bisect_left from typing import List from comment_parser.parsers import common def extract_comments(code: str) -> List[common.Comment]: """Extracts a list of comments from the given HTML family source code. Comments are represented with the Comment class found in the common module. HTML family comments come in one form, comprising all text within '' markers. Comments cannot be nested. Args: code: String containing code to extract comments from. Returns: Python list of common.Comment in the order that they appear in the code.. Raises: common.UnterminatedCommentError: Encountered an unterminated multi-line comment. """ pattern = r""" (?P (\"([^\"\n])*\")+) | (?P ) | (?P ) | (?P ' comments = html_parser.extract_comments(code) expected = [common.Comment('comment', 1, multiline=False)] self.assertEqual(comments, expected) def testMultilineComment(self): code = '' comments = html_parser.extract_comments(code) expected = [common.Comment('multi-line\ncomment', 1, multiline=True)] self.assertEqual(comments, expected) def testTwoSeparateSingleComment(self): code = '\n' comments = html_parser.extract_comments(code) expected = [ common.Comment('comment1', 1, multiline=False), common.Comment('comment2', 2, multiline=False), ] self.assertEqual(comments, expected) def testLayeredComment(self): code = '' comments = html_parser.extract_comments(code) expected = [common.Comment(' comment not a comment -->' comments = html_parser.extract_comments(code) expected = [common.Comment('comment', 1, multiline=False)] self.assertEqual(comments, expected) def testSideBySideComment(self): code = ' ... ' comments = html_parser.extract_comments(code) expected = [ common.Comment('comment1', 1, multiline=False), common.Comment('comment2', 1, multiline=False), ] self.assertEqual(comments, expected) def testUnterminatedComment(self): code = '' comments = html_parser.extract_comments(code) self.assertEqual(comments, []) jeanralphaviles-comment_parser-4a2f6e2/comment_parser/parsers/tests/js_parser_test.py000066400000000000000000000036561473271112000315610ustar00rootroot00000000000000#!/usr/bin/python """Tests for comment_parser.parsers.js_parser.py""" import unittest from comment_parser.parsers import common from comment_parser.parsers import js_parser class JsParserTest(unittest.TestCase): def testSingleLineComment(self): code = '// single line comment' comments = js_parser.extract_comments(code) expected = [common.Comment(code[2:], 1, multiline=False)] self.assertEqual(comments, expected) def testLineCommentInSingleQuotedLiteral(self): code = "msg = '// this is not a comment'" comments = js_parser.extract_comments(code) self.assertEqual(comments, []) def testLineCommentInDoubleQuotedLiteral(self): code = 'msg = "// this is not a comment"' comments = js_parser.extract_comments(code) self.assertEqual(comments, []) def testMultiLineComment(self): code = '/* multiline\ncomment */' comments = js_parser.extract_comments(code) expected = [common.Comment(code[2:-2], 1, multiline=True)] self.assertEqual(comments, expected) def testMultiLineCommentWithStars(self): code = "/***************/" comments = js_parser.extract_comments(code) expected = [common.Comment(code[2:-2], 1, multiline=True)] self.assertEqual(comments, expected) def testMultiLineCommentInSingleLiteral(self): code = "msg = '/* This is not a\\nmultiline comment */'" comments = js_parser.extract_comments(code) self.assertEqual(comments, []) def testMultiLineCommentInDoubleLiteral(self): code = 'msg = "/* This is not a\\nmultiline comment */"' comments = js_parser.extract_comments(code) self.assertEqual(comments, []) def testMultiLineCommentUnterminated(self): code = 'a = 1 /* Unterminated\\n comment' self.assertRaises(common.UnterminatedCommentError, js_parser.extract_comments, code) jeanralphaviles-comment_parser-4a2f6e2/comment_parser/parsers/tests/python_parser_test.py000066400000000000000000000022551473271112000324600ustar00rootroot00000000000000#!/usr/bin/python """Tests for comment_parser.parsers.python_parser.py""" import unittest from comment_parser.parsers import common from comment_parser.parsers import python_parser class PythonParserTest(unittest.TestCase): def testComment(self): code = '# comment' comments = python_parser.extract_comments(code) expected = [common.Comment(code[1:], 1, multiline=False)] self.assertEqual(comments, expected) def testCommentInSingleQuotedString(self): code = "'this is # not a comment'" comments = python_parser.extract_comments(code) self.assertEqual(comments, []) def testCommentInDoubleQuotedString(self): code = '"this is # not a comment"' comments = python_parser.extract_comments(code) self.assertEqual(comments, []) def testNestedStringSingleOutside(self): code = "'this is \"# not a comment\"'" comments = python_parser.extract_comments(code) self.assertEqual(comments, []) def testNestedStringDoubleOutside(self): code = '"this is \'# not a comment\'"' comments = python_parser.extract_comments(code) self.assertEqual(comments, []) jeanralphaviles-comment_parser-4a2f6e2/comment_parser/parsers/tests/ruby_parser_test.py000066400000000000000000000046111473271112000321160ustar00rootroot00000000000000#!/usr/bin/python """Tests for comment_parser.parsers.ruby_parser.py""" import unittest from comment_parser.parsers import common from comment_parser.parsers import ruby_parser class ShellParserTest(unittest.TestCase): def testComment(self): code = '# comment' comments = ruby_parser.extract_comments(code) expected = [common.Comment(code[1:], 1, multiline=False)] self.assertEqual(comments, expected) def testCommentInSingleQuotedString(self): code = "'this is # not a comment'" comments = ruby_parser.extract_comments(code) self.assertEqual(comments, []) def testCommentInDoubleQuotedString(self): code = '"this is # not a comment"' comments = ruby_parser.extract_comments(code) self.assertEqual(comments, []) def testNestedStringSingleOutside(self): code = "'this is \"# not a comment\"'" comments = ruby_parser.extract_comments(code) self.assertEqual(comments, []) def testNestedStringDoubleOutside(self): code = '"this is \'# not a comment\'"' comments = ruby_parser.extract_comments(code) self.assertEqual(comments, []) def testEscapedSingleQuote(self): code = "\\'# this is a comment" comments = ruby_parser.extract_comments(code) expected = [common.Comment(code[3:], 1, multiline=False)] self.assertEqual(comments, expected) def testEscapedDoubleQuote(self): code = '\\"# this is a comment' comments = ruby_parser.extract_comments(code) expected = [common.Comment(code[3:], 1, multiline=False)] self.assertEqual(comments, expected) def testDoubleComment(self): code = '# this is not # another comment' comments = ruby_parser.extract_comments(code) expected = [common.Comment(code[1:], 1, multiline=False)] self.assertEqual(comments, expected) def testLiteralsSeparatedByComment(self): code = r"'This is' # 'a comment'" comments = ruby_parser.extract_comments(code) expected = [common.Comment(code[11:], 1, multiline=False)] self.assertEqual(comments, expected) def testDifferentLiteralsSeparatedByComment(self): code = r''''This is' # "a comment"''' comments = ruby_parser.extract_comments(code) expected = [common.Comment(code[11:], 1, multiline=False)] self.assertEqual(comments, expected) jeanralphaviles-comment_parser-4a2f6e2/comment_parser/parsers/tests/shell_parser_test.py000066400000000000000000000034631473271112000322500ustar00rootroot00000000000000#!/usr/bin/python """Tests for comment_parser.parsers.shell_parser.py""" import unittest from comment_parser.parsers import common from comment_parser.parsers import shell_parser class ShellParserTest(unittest.TestCase): def testComment(self): code = '# comment' comments = shell_parser.extract_comments(code) expected = [common.Comment(code[1:], 1, multiline=False)] self.assertEqual(comments, expected) def testEscapedComment(self): code = r'\# not a comment' comments = shell_parser.extract_comments(code) self.assertEqual(comments, []) def testCommentInSingleQuotedString(self): code = "'this is # not a comment'" comments = shell_parser.extract_comments(code) self.assertEqual(comments, []) def testCommentInDoubleQuotedString(self): code = '"this is # not a comment"' comments = shell_parser.extract_comments(code) self.assertEqual(comments, []) def testNestedStringSingleOutside(self): code = "'this is \"# not a comment\"'" comments = shell_parser.extract_comments(code) self.assertEqual(comments, []) def testNestedStringDoubleOutside(self): code = '"this is \'# not a comment\'"' comments = shell_parser.extract_comments(code) self.assertEqual(comments, []) def testEscapedSingleQuote(self): code = "\\'# this is a comment" comments = shell_parser.extract_comments(code) expected = [common.Comment(code[3:], 1, multiline=False)] self.assertEqual(comments, expected) def testEscapedDoubleQuote(self): code = '\\"# this is a comment' comments = shell_parser.extract_comments(code) expected = [common.Comment(code[3:], 1, multiline=False)] self.assertEqual(comments, expected) jeanralphaviles-comment_parser-4a2f6e2/requirements-dev.txt000066400000000000000000000001171473271112000243460ustar00rootroot00000000000000pylint==3.3.3 pytest==8.3.4 pytype==2024.10.11 setuptools==75.6.0 yapf==0.43.0 jeanralphaviles-comment_parser-4a2f6e2/requirements.txt000066400000000000000000000000251473271112000235700ustar00rootroot00000000000000python-magic==0.4.27 jeanralphaviles-comment_parser-4a2f6e2/setup.cfg000066400000000000000000000001121473271112000221220ustar00rootroot00000000000000[metadata] description-file = README.md [pytype] inputs = comment_parser jeanralphaviles-comment_parser-4a2f6e2/setup.py000066400000000000000000000016211473271112000220210ustar00rootroot00000000000000from platform import python_version from setuptools import setup def readme(): with open('README.md') as readme_file: return readme_file.read() setup( name='comment_parser', version='1.2.5', description='Parse comments from various source files.', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Documentation', 'License :: OSI Approved :: MIT License' ], url='http://github.com/jeanralphaviles/comment_parser', author='Jean-Ralph Aviles', author_email='jeanralph.aviles+pypi@gmail.com', license='MIT', long_description=readme(), long_description_content_type='text/markdown', packages=['comment_parser', 'comment_parser.parsers'], install_requires=['python-magic>=0.4.27'], zip_safe=False, python_requires='>=3.13', )