diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..c3bbfb5 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,41 @@ +name: Python Application CI + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.x' # Use a generic Python 3 version + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install nltk flake8 + # The chatcoder.py script itself calls nltk.download(). + # We need to ensure these resources are available for any import/run checks. + # Running this command in the workflow to pre-download. + python -c "import nltk; nltk.download('punkt'); nltk.download('averaged_perceptron_tagger')" + + - name: Lint with Flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + + - name: Test basic script import + run: | + python -c "import chatcoder" + + # Future step: Run unit tests (if they become viable) + # - name: Run Unit Tests + # run: | + # python -m unittest discover -s . -p "test_*.py" diff --git a/README.md b/README.md index 327525c..3250205 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,51 @@ -# NaturalLanguagecoder -a small utility to take prompt strings and refine them into a structured format for better interpretation by LLM's. It's very raw and in need of detailing and cleanup work as well as interface enhancement etc. +# NaturalLanguageCoder +[![Python Application CI](https://github.com/YOUR_USERNAME/YOUR_REPOSITORY/actions/workflows/main.yml/badge.svg)](https://github.com/YOUR_USERNAME/YOUR_REPOSITORY/actions/workflows/main.yml) +## Description +A Python utility that converts natural language instructions into a basic code structure. It uses NLTK for tokenization and part-of-speech tagging to perform a rudimentary analysis and conversion. This tool is an initial exploration and has significant room for improvement in terms of accuracy, complexity of conversions, and user interface. + +## Current Features +* Accepts natural language input via a simple Tkinter GUI. +* Tokenizes and tags words using NLTK. +* Converts verbs into function calls (e.g., "print" -> "print()"). +* Treats nouns as potential variables or objects. +* Allows saving the generated code snippet to a file named `output.py`. + +## Limitations +* The conversion logic is very basic and rule-based. It does not understand context, complex grammar, or specific programming language syntax beyond simple function calls and variable names. +* Error handling is minimal. +* The GUI is very basic. + +## Installation +1. Clone the repository: `git clone ` +2. Navigate to the project directory: `cd NaturalLanguagecoder` +3. Install required libraries: `pip install nltk tkinter` +4. The first time you run the script, NLTK will download necessary resources ('punkt' and 'averaged_perceptron_tagger'). If this fails, you may need to run Python interactively and execute: + ```python + import nltk + nltk.download('punkt') + nltk.download('averaged_perceptron_tagger') + ``` + +## Usage +1. Run the script: `python chatcoder.py` +2. Enter your natural language instruction in the input field (e.g., "create variable data and print hello"). +3. Click "Convert to Code". +4. The generated code structure will appear in the text area below. +5. Click "Save" to save the output to `output.py` in the same directory. + +## Example Conversion +* Input: `define function process data` +* Output: `define() function() process() data ` (Illustrative of current simple logic) + +## Contributing +Contributions are welcome! If you'd like to improve NaturalLanguageCoder, please consider: + * Enhancing the parsing and code generation logic. + * Adding support for more complex programming constructs. + * Improving the user interface. + * Adding comprehensive error handling. + * Expanding test coverage. +Please fork the repository, make your changes on a new branch, and submit a pull request. + +## License +This project is licensed under the terms of the LICENSE file. diff --git a/__pycache__/chatcoder.cpython-310.pyc b/__pycache__/chatcoder.cpython-310.pyc new file mode 100644 index 0000000..ddf25bf Binary files /dev/null and b/__pycache__/chatcoder.cpython-310.pyc differ diff --git a/__pycache__/test_chatcoder.cpython-310.pyc b/__pycache__/test_chatcoder.cpython-310.pyc new file mode 100644 index 0000000..3413e53 Binary files /dev/null and b/__pycache__/test_chatcoder.cpython-310.pyc differ diff --git a/test_chatcoder.py b/test_chatcoder.py new file mode 100644 index 0000000..47c0e88 --- /dev/null +++ b/test_chatcoder.py @@ -0,0 +1,79 @@ +import unittest +from unittest.mock import patch, MagicMock +import sys + +# Define global mocks to be used by sys.modules patcher +mock_tk_module_for_setup = MagicMock(name='setup_mock_tk') +mock_ttk_module_for_setup = MagicMock(name='setup_mock_ttk') +modules_to_mock_for_setup = { + 'tkinter': mock_tk_module_for_setup, + 'tkinter.ttk': mock_ttk_module_for_setup +} + +# Placeholders for patchers and imported modules/classes +sys_modules_patcher_module_level = None +nltk_download_patcher_module_level = None +CodeConverterApp_module_level = None +nltk_module_for_patching = None # To store the imported nltk module + +def setUpModule(): + """Called once, before any tests in this module run.""" + global sys_modules_patcher_module_level, nltk_download_patcher_module_level + global CodeConverterApp_module_level, nltk_module_for_patching + + sys_modules_patcher_module_level = patch.dict(sys.modules, modules_to_mock_for_setup) + sys_modules_patcher_module_level.start() + + # Patch nltk.download before chatcoder (which imports nltk) is imported + nltk_download_patcher_module_level = patch('nltk.download', MagicMock(return_value=True)) + nltk_download_patcher_module_level.start() + + # Import nltk module itself into a global for direct patching later + import nltk as imported_nltk_module + nltk_module_for_patching = imported_nltk_module + + # Import CodeConverterApp now. It will use the above imported_nltk_module if it also does 'import nltk'. + from chatcoder import CodeConverterApp as imported_app + CodeConverterApp_module_level = imported_app + + +def tearDownModule(): + """Called once, after all tests in this module have run.""" + if nltk_download_patcher_module_level: + nltk_download_patcher_module_level.stop() + if sys_modules_patcher_module_level: + sys_modules_patcher_module_level.stop() + +class TestCodeConverterAppSimplified(unittest.TestCase): + + def test_convert_to_code_logic(self): + # Use patch.object to patch word_tokenize and pos_tag directly on the + # nltk module object that was imported in setUpModule. + with patch.object(nltk_module_for_patching, 'word_tokenize', MagicMock(return_value=['test', 'function'])) as mock_word_tokenize_arg, \ + patch.object(nltk_module_for_patching, 'pos_tag', MagicMock(return_value=[('test', 'VB'), ('function', 'NN')])) as mock_pos_tag_arg: + + # Arrange + # NLTK mocks are set up by the with statement's patch.object + + try: + app = CodeConverterApp_module_level() + except Exception as e: + self.fail(f"Failed to instantiate CodeConverterApp: {e}") + + app.input_entry = MagicMock(name='mock_input_entry') + app.input_entry.get = MagicMock(return_value="test function") + + app.output_text = MagicMock(name='mock_output_text') + app.output_text.delete = MagicMock() + app.output_text.insert = MagicMock() + + # Act + app.convert_to_code() + + # Assert + mock_word_tokenize_arg.assert_called_once_with("test function") + mock_pos_tag_arg.assert_called_once_with(['test', 'function']) + app.output_text.insert.assert_called_once_with(mock_tk_module_for_setup.END, "test() function ") + +if __name__ == '__main__': + unittest.main()