From 53912d3850c294af501abc238df8b3b72d09d671 Mon Sep 17 00:00:00 2001 From: Nathaniel Handan <87228776+Tinny-Robot@users.noreply.github.com> Date: Fri, 27 Oct 2023 02:30:46 +0100 Subject: [PATCH 1/5] Create python-app.yml --- .github/workflows/python-app.yml | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/python-app.yml diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 0000000..d53b731 --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,41 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python application + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python 3.10 + uses: actions/setup-python@v3 + with: + python-version: "3.10" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest pylint + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - 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 with pytest + run: | + for file in $(find . -name "*.py"); do + python your_script.py $file + done From fade1addd537f931431fb4cf35763c60e48af981 Mon Sep 17 00:00:00 2001 From: Nathaniel Handan <87228776+Tinny-Robot@users.noreply.github.com> Date: Fri, 27 Oct 2023 02:02:58 +0000 Subject: [PATCH 2/5] feat: Add functions for XML to JSON, JSON to XML, and XML to CSV conversion --- CONTRIBUTING.md | 18 ++++++- examples.py | 3 ++ textbin/textbin.py | 115 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 128 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 022bc73..673608d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,2 +1,16 @@ -# contributions -your contributions will be highly appreciated. I hope it be of help to you thank you. c-o-m-o-n +# Contributing + +Thank you for considering contributing to our project! We welcome all contributions, big or small, and appreciate your time and effort. + +To get started, please take a look at our [README.md](./README.md) file for an overview of the project and its goals. If you have any questions or need help with anything, please don't hesitate to reach out to us. + +When submitting a contribution, please follow these guidelines: + +- Make sure your code is well-documented and easy to understand. +- Write clear commit messages that describe the changes you've made. +- Test your code thoroughly to ensure it works as expected. +- Follow our code style and formatting guidelines. +- Be respectful and professional in all interactions with other contributors and maintainers. + +Thank you again for your contributions, and we look forward to working with you! +@c-o-m-o-n \ No newline at end of file diff --git a/examples.py b/examples.py index 1f855f3..7bc482f 100644 --- a/examples.py +++ b/examples.py @@ -9,6 +9,9 @@ - base64_to_json: Converts a base64-encoded string to a JSON object. - csv_to_json: Converts a CSV string to a JSON object. - json_to_csv: Converts a JSON object to a CSV string. +- xml_to_json: Converts an XML string to a JSON object. +- json_to_xml: Converts a JSON object to an XML string. +- xml_to_csv: Converts an XML string to a CSV file. ----- To begin, create an object from the Textbin() class, which you'll use to access all the methods. diff --git a/textbin/textbin.py b/textbin/textbin.py index 710af1c..65e3c72 100644 --- a/textbin/textbin.py +++ b/textbin/textbin.py @@ -2,8 +2,24 @@ import base64 from typing import Union import csv +import xml.etree.ElementTree as ET class Textbin: + """ + A class for converting between various text formats. + + Methods: + - to_binary: Converts text to binary representation. + - to_text: Converts binary representation to text. + - json_to_base64: Converts a JSON object to a base64-encoded string. + - base64_to_json: Converts a base64-encoded string to a JSON object. + - xml_to_json: Converts an XML string to a JSON object. + - json_to_xml: Converts a JSON object to an XML string. + - xml_to_csv: Converts an XML string to a CSV file. + """ + def __init__(self): + pass + def to_binary(self, text: str) -> str: """Convert text to binary representation.""" binary = " ".join(format(ord(i), "b") for i in str(text)) @@ -121,17 +137,104 @@ def bin_to_json(self, binary: str) -> Union[dict, list]: except Exception as e: raise ValueError(f"Error converting binary to JSON: {e}") + + def xml_to_json(self, xml_string: str) -> Union[dict, list]: + """Convert an XML string to a JSON object.""" + try: + root = ET.fromstring(xml_string) + json_data = self._element_to_dict(root) + return json_data + except ET.ParseError as e: + raise ValueError(f"Invalid XML data: {e}") + except Exception as e: + raise ValueError(f"Error converting from XML to JSON: {e}") + + def json_to_xml(self, json_data: Union[dict, list]) -> str: + """Convert a JSON object to an XML string.""" + try: + root = self._dict_to_element(json_data) + xml_string = ET.tostring(root, encoding="unicode") + return xml_string + except Exception as e: + raise ValueError(f"Error converting from JSON to XML: {e}") + + def xml_to_csv(self, xml_string: str, csv_file: str) -> None: + """Convert an XML string to a CSV file.""" + try: + root = ET.fromstring(xml_string) + with open(csv_file, "w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + header = [] + for child in root: + row = [] + for key, value in child.attrib.items(): + if key not in header: + header.append(key) + row.append(value) + writer.writerow(row) + writer.writerow(header) + except ET.ParseError as e: + raise ValueError(f"Invalid XML data: {e}") from e + except Exception as e: + raise ValueError(f"Error converting from XML to CSV: {e}") from e + + + def _element_to_dict(self, element: ET.Element) -> Union[dict, list]: + """Convert an ElementTree element to a dictionary.""" + if element: + if element.attrib: + return {element.tag: element.attrib} + children = element.getchildren() + if children: + out = {} + for child in children: + result = self._element_to_dict(child) + if child.tag in out: + if isinstance(out[child.tag], list): + out[child.tag].append(result) + else: + out[child.tag] = [out[child.tag], result] + else: + out[child.tag] = result + return {element.tag: out} + return {element.tag: element.text} + return None + + def _dict_to_element(self, data: Union[dict, list]) -> ET.Element: + """Convert a dictionary to an ElementTree element.""" + if isinstance(data, dict): + items = data.items() + elif isinstance(data, list): + items = enumerate(data) + else: + raise ValueError(f"Invalid data type: {type(data)}") + elem = ET.Element("item") + for key, value in items: + if isinstance(value, dict): + child = self._dict_to_element(value) + child.tag = key + elem.append(child) + elif isinstance(value, list): + for item in value: + child = self._dict_to_element(item) + child.tag = key + elem.append(child) + else: + child = ET.Element(key) + child.text = str(value) + elem.append(child) + return elem + if __name__ == "__main__": - textbin = Textbin() - + textbin = Textbin() word = {"foo": "bar"} try: converted_word = textbin.json_to_base64(word) - print(converted_word) # Output: eyJmb28iOiAiYmFyIn0= - - base64_string = "eyJmb28iOiAiYmFyIn0=" - converted_binary = textbin.base64_to_json(base64_string) + print(converted_word) # Output: eyJmb28iOiAiYmFyIn0= + BASE64_STRING = "eyJmb28iOiAiYmFyIn0=" + converted_binary = textbin.base64_to_json(BASE64_STRING) print(converted_binary) # Output: {'foo': 'bar'} + except ValueError as e: print(f"Error: {e}") From cf488a69e7b030d4fed8b1d58ccb108f92308846 Mon Sep 17 00:00:00 2001 From: Nathaniel Handan <87228776+Tinny-Robot@users.noreply.github.com> Date: Fri, 27 Oct 2023 03:08:09 +0100 Subject: [PATCH 3/5] Update python-app.yml --- .github/workflows/python-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index d53b731..d1388d0 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -37,5 +37,5 @@ jobs: - name: Test with pytest run: | for file in $(find . -name "*.py"); do - python your_script.py $file + pylint $file done From 7b61f68f62d4806d713e3b41978871980e4f215b Mon Sep 17 00:00:00 2001 From: Nathaniel Handan <87228776+Tinny-Robot@users.noreply.github.com> Date: Fri, 27 Oct 2023 03:29:11 +0100 Subject: [PATCH 4/5] Update python-app.yml --- .github/workflows/python-app.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index d1388d0..8c333e6 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -36,6 +36,4 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with pytest run: | - for file in $(find . -name "*.py"); do - pylint $file - done + pylint textbin/textbin.py From 5b905574f658b03677e0e4a3735b42a6c1bf0632 Mon Sep 17 00:00:00 2001 From: Nathaniel Handan <87228776+Tinny-Robot@users.noreply.github.com> Date: Fri, 27 Oct 2023 03:30:42 +0100 Subject: [PATCH 5/5] Update python-app.yml --- .github/workflows/python-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 8c333e6..e3a8c53 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -36,4 +36,4 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with pytest run: | - pylint textbin/textbin.py + pylint --fail-under=7.8 textbin/textbin.py