diff --git a/.gitignore b/.gitignore index 37f8393..9e60762 100644 --- a/.gitignore +++ b/.gitignore @@ -128,4 +128,7 @@ dmypy.json # Pyre type checker .pyre/ *.json -test_db.py \ No newline at end of file +test_db.py +test.py +*.log +quick_db_output/ \ No newline at end of file diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..3e856e9 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,24 @@ +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.12" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Optionally build your docs in additional formats such as PDF and ePub +formats: + - pdf + - epub + +python: + install: + - requirements: docs/requirements.txt \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 91c0acf..2fbbb87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,32 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Initial Release] +## Version 0.0.5 + +- Bug fixes for duplicate values in insert queries +- Bug fixes for already existing tables in insert queries +- debug mode added for logging + +## Version 0.0.4 + +- Support for multi insert queries added + +## Version 0.0.3 + +- `dum_db` parameter changed to `commit` in insert queries +- Bug fixes + +## Version 0.0.2 + +- Added support for `schema` and `table` in `Database` class +- Support for logger added +- Support for multiple tables in a database added +- Support for drop table added +- Support for `select` , `insert`, `update` and `delete` queries added + +## [Initial Release] Version 0.0.1 - Initial release with basic database features++ - Initial documentation++ - Initial tests++ + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..b7954f8 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at pycontributors@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ac1a30e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,79 @@ +# Contributing to QuickDB + +We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's: + +- Reporting a bug +- Discussing the current state of the code +- Submitting a fix +- Proposing new features +- Becoming a maintainer + +## Steps to contribute + +- Comment on the issue you want to work on. Make sure it's not assigned to someone else. + +### Making a PR + +> - Make sure you have been assigned the issue to which you are making a PR. +> - If you make PR before being assigned, It may be labeled `invalid` and closed without merging. + +- Fork the repo and clone it on your machine. +- Add a upstream link to main branch in your cloned repo + + ```sh + git remote add upstream https://github.com/py-contributors/quickdb.git + ``` + +- Keep your cloned repo upto date by pulling from upstream (this will also avoid any merge conflicts while committing new changes) + + ```sh + git pull upstream master + ``` + +- Create your feature branch + + ```sh + git checkout -b + ``` + +- Commit all the changes + + ```sh + git commit -am "Meaningful commit message" + ``` + +- Push the changes for review + + ```sh + git push origin + ``` + +- Create a PR from our repo on Github. + +### Additional Notes + +- Any changes should be made in the `dev` branch. +- Changes should be logged in the `CHANGELOG.md` file. +- Code should be properly commented to ensure it's readability. +- If you've added code that should be tested, add tests as comments. +- Make sure your code properly formatted. +- Issue that pull request! + +## Issue suggestions/Bug reporting + +When you are creating an issue, make sure it's not already present. Furthermore, provide a proper description of the changes. If you are suggesting any code improvements, provide through details about the improvements. + +**Great Issue suggestions** tend to have: + +- A quick summary of the changes. +- In case of any bug provide steps to reproduce + - Be specific! + - Give sample code if you can. + - What you expected would happen + - What actually happens + - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work) + + +## License + +By contributing, you agree that your contributions will be licensed under its [MIT License](http://choosealicense.com/licenses/mit/). diff --git a/README.md b/README.md index 67c0e49..05277e5 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,72 @@ -# python-db +

Quick DB ⚡ 0.0.5

+

Light weight database for python, with a simple API and a simple file format. it is not meant to be a full featured database, but rather a simple way to store data in a file. -it's written in python, and is compatible with python 3.6 and above. +it's written in python, and is compatible with python 3.6 and above.

+

+github stars +github forks +code size +

+

+pypi status +docs +dependices +

+

+discord invite +total contributors +

## Features * Simple API -* Colorful output -* Easy to use +* CLI support with colorful output +* Easy to use * CLI interface * Open source -## Documentation +## Documentation/Tutorial -The documentation is available at [not yet available]() +The documentation is available at [Quick DB](https://quickdb.readthedocs.io/en/latest/) ## Installation -You can install python-db using pip: +You can install the package using pip: - pip install python-db +### [Stable version](https://pypi.org/project/quickDatabase/) +```bash +pip install quickdatabase +``` + +### [Unstable and latest version](https://test.pypi.org/project/quickDatabase/) + +```bash +pip install -i https://test.pypi.org/simple/ quickDatabase +``` ## Usage -To use python-db, you need to import it: +To use QuickDB, you need to import it: + +```bash +from quickdb import QuickDB +``` + +## CONTRIBUTING + +If you want to contribute to this project, you can do so by forking the repository and making a pull request. +Check out the [CONTRIBUTING.md](/CONTRIBUTING.md) file for more information. + +## LICENSE + +This project is licensed under the MIT License - see the [LICENSE](/LICENSE) file for details + +## Contributors - from python_db import Database + + + diff --git a/docs/as_module.rst b/docs/as_module.rst new file mode 100644 index 0000000..067582c --- /dev/null +++ b/docs/as_module.rst @@ -0,0 +1,54 @@ +Use as library +============== + +``` +from quickdb import QuickDB +``` + +Initialize the database +------------------------ + +``` +db_object = QuickDB(db_path="quickdb.json") +``` + +Create a table +-------------- + +It will create a table schema with the given columns and primary key. +If the table already exists, it will not create a new table. + +``` +table_name = 'employee' +columns = ['serial', 'name', 'age', 'city', 'country', 'email', 'phone', 'salary'] +primary_key = 'serial' +db_object.create_table(table_name, columns, primary_key) +``` + +Insert data +----------- + +It will insert the data into the table. if primary_key is already present, it will not insert the data. +overwrite need to pass as True to overwrite the data. + +``` +db_object.insert_into(table_name=table_name, + value=[1, 'John Doe', 30, 'New York', 'USA', 'john@gmail.com', '1234567890', 50000], commit=True) +db_object.insert_into(table_name=table_name, + value=[1, 'John Doe', 30, 'New York', 'USA', 'john@gmail.com', '1234567890', 50000], commit=True, overwrite=True) +db_object.dump_db() # Save the data to the file +``` + +Insert multiple data +-------------------- + +If you want to insert multiple data at once, you can use the below method. + +``` +# insert_into_many +values = [ + [3, 'John Doe', 30, 'New York', 'USA', 'd@gmail.com', '1234567890', 50000], + [4, 'John Doe', 30, 'New York', 'USA', 'f@gs', '1234567890', 50000] +] +db_object.insert_into_many(table_name=table_name, values=values, commit=True) +``` diff --git a/docs/conf.py b/docs/conf.py index 0d8b198..06461eb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,7 +1,7 @@ from datetime import datetime project = 'quickDB' -release = '0.0.1' +release = '0.0.5' templates_path = ['_templates'] source_suffix = ".rst" master_doc = "index" @@ -13,4 +13,4 @@ html_theme = 'sphinx_rtd_theme' # 'pydata_sphinx_theme' 'alabaster' html_static_path = ['_static'] exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.venv'] -html_sidebars = { '**': ['globaltoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html'] } \ No newline at end of file +html_sidebars = {'**': ['globaltoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html']} diff --git a/docs/index.rst b/docs/index.rst index 0d45f4c..569c188 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,4 +4,20 @@ Welcome to QuickDB's documentation! ===================================== -![Download badge](http://pepy.tech/badge/pickledb) \ No newline at end of file +Light weight database for python, with a simple API and a simple file format. +it is not meant to be a full featured database, but rather a simple way to store data in a file. +it's written in python, and is compatible with python 3.6 and above. + +Features +-------- + +- Simple API +- Easy to use +- Open source + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + installation.rst + as_module.rst \ No newline at end of file diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000..257463f --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,29 @@ +Installation +============ + +Install Via Pip(recommended) +--------------------------- + +.. code-block:: bash + + pip install quickdatabase + +Install Via Source(Unreleased/latest) +----------------- + +.. code-block:: bash + + git clone https://github.com/py-contributors/quickdb + cd quickdb + python setup.py install + +Why QuickDB? +------------ + +QuickDB is a light weight database for python, with a simple API and a simple file format. It is not meant to be a full +featured database, but rather a simple way to store data in a file. It's written in python, and is compatible with python +3.6 and above. The main goal of QuickDB is to provide a simple, faster and easy to use database for python developers. + + + + \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..cbf1e36 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,2 @@ +sphinx +sphinx-rtd-theme diff --git a/quickdb_/__init__.py b/quickdb/__init__.py similarity index 60% rename from quickdb_/__init__.py rename to quickdb/__init__.py index d90e796..7ee5dc5 100644 --- a/quickdb_/__init__.py +++ b/quickdb/__init__.py @@ -1,3 +1,3 @@ from quickdb.main import QuickDB -__all__ = ['QuickDB'] \ No newline at end of file +__all__ = ["QuickDB"] diff --git a/quickdb/main.py b/quickdb/main.py new file mode 100644 index 0000000..67a3d5c --- /dev/null +++ b/quickdb/main.py @@ -0,0 +1,244 @@ +import os +import json +import pandas as pd +import logging + + +class Logger: + """ Logger class to log the messages """ + def __init__(self, log_path): + self.log_path = log_path + self.logger = logging.getLogger(__name__) + + logging.basicConfig(filename=self.log_path, + level=logging.INFO, + format='%(asctime)s:%(levelname)s:%(lineno)d:%(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + filemode='a') + self.logger.info(f"Logger initialized with log path {self.log_path}") + + +class QuickDB(Logger): + """ python database.py """ + def __init__(self, db_path="db.json", db_drop_path="quick_db_output", + overwrite_db=False, debug=True, db_log_path="dedug.log"): + super().__init__(db_log_path) + """ Initialize the database """ + + self.db_path = db_path + self.debug = debug + self.overwrite_db = overwrite_db + self.db = self.__init_db() + self.schema = self.db['schema'] + self.database = self.db['database'] + self.db_drop_path = db_drop_path + self.db_log_path = db_log_path + self.logger.info("-"*50) + + def __load_db_from_file(self): + """ Load the database from the file """ + with open(self.db_path, 'r') as f: + return json.load(f) + + def __init_db(self): + """" Initialize the database """ + + if not self.overwrite_db and os.path.exists(self.db_path): + self.logger.info(f"Loading database from {self.db_path}") + return self.__load_db_from_file() + + if self.overwrite_db and os.path.exists(self.db_path): + self.logger.info(f"Overwriting database from {self.db_path}") + self.clear_database() + return self.db + + self.logger.info(f"Creating new database at {self.db_path}") + return {"database": {}, "schema": {}} + + def dump_db(self): + """ Dump the database to the file """ + try: + with open(self.db_path, 'w+') as f: + json.dump(self.db, f, indent=4) + return True + except json.JSONDecodeError: + return False + + def dumb_table(self, table_name, output_format='json'): + """ Dump the table to the file """ + if table_name not in self.db['database']: + return False + + os.makedirs(self.db_drop_path, exist_ok=True) + + table_data = self.db['database'][table_name] + + if output_format == 'json': + with open(os.path.join(self.db_drop_path, f"{table_name}.json"), 'w+') as f: + json.dump(table_data, f, indent=4) + self.logger.info(f"Table {table_name} dumped to {table_name}.json") + return True + + if output_format == 'csv': + df = pd.DataFrame(table_data).T + df.to_csv(os.path.join(self.db_drop_path, f"{table_name}.csv"), index=False) + self.logger.info(f"Table {table_name} dumped to {table_name}.csv") + return True + + if output_format == 'excel': + df = pd.DataFrame(table_data) + df.to_excel(os.path.join(self.db_drop_path, f"{table_name}.xlsx"), index=False) + self.logger.info(f"Table {table_name} dumped to {table_name}.xlsx") + return True + + if output_format == 'df': + return pd.DataFrame(table_data) + + if output_format == 'print': + print(table_data) + return True + + def create_table(self, table_name, columns_list, primary_key=None): + """ Create the schema of the database """ + + if table_name in self.schema: + self.logger.error(f"Table {table_name} already exists") + return False + + if primary_key not in columns_list: + raise ValueError(f"Primary key {primary_key} not in columns list") + + primary_key_index = columns_list.index(primary_key) + + self.schema[table_name] = { + "columns_list": columns_list, + "primary_key": primary_key, + "primary_key_index": primary_key_index + } + + self.db['schema'] = self.schema + self.db['database'][table_name] = {} + self.logger.info(f"Table {table_name} created with columns {columns_list} and primary key {primary_key}") + self.dump_db() + + def get_table_names(self): + """ Get all the tables in the database""" + return list(self.schema.keys()) + + def get_table(self, table_name): + """ Get the table schema """ + return self.schema[table_name] + + def get_table_columns(self, table_name): + """ Get the columns of the table """ + return self.schema[table_name]['columns_list'] + + def get_table_primary_key(self, table_name): + """ Get the primary key of the table """ + return self.schema[table_name]['primary_key'] + + def insert_into(self, table_name, value, overwrite=False, commit=False): + """ Set the key-value pair in the database """ + primary_value = str(value[self.schema[table_name]['primary_key_index']]) + columns_list = self.schema[table_name]['columns_list'] + + database_keys = self.db['database'][table_name].keys() + + if primary_value in database_keys and not overwrite: + self.logger.error(f"Primary key {primary_value} already exists in {table_name}") + return False + + if len(value) != len(columns_list): + self.logger.error(f"Length of value {value} does not match columns list {columns_list}") + return False + + self.db["database"][table_name][primary_value] = dict(zip(columns_list, value)) + self.logger.info(f"Inserted {value} into {table_name}") + + if commit: + self.dump_db() + return True + + def insert_into_many(self, table_name, values, overwrite=False, commit=False): + """ Set the key-value pair in the database """ + for value in values: + primary_value = str(value[self.schema[table_name]['primary_key_index']]) + columns_list = self.schema[table_name]['columns_list'] + + if primary_value in self.db['database'][table_name].keys() and not overwrite: + self.logger.error(f"Primary key {primary_value} already exists in {table_name}") + continue + + if len(value) != len(columns_list): + self.logger.error(f"Length of value {value} does not match columns list {columns_list}") + continue + + self.db["database"][table_name][primary_value] = dict(zip(columns_list, value)) + self.logger.info(f"Inserted {value} into {table_name}") + + if commit: + self.dump_db() + return True + + def get_db(self): + """ Get the database along with the schema """ + return self.db + + def get_table_data(self, table_name): + """ Get the table data """ + return self.db['database'][table_name] + + def clear_database(self): + """ Clear the database """ + self.db = {"database": {}, "schema": {}} + self.dump_db() + self.logger.info("Database cleared") + return True + + def drop_table(self, table_name): + """ Drop the table from the database """ + if table_name in self.db['database']: + del self.db['database'][table_name] + del self.db['schema'][table_name] + self.dump_db() + self.logger.info(f"Table {table_name} dropped") + return True + return False + + def delete(self, table_name, primary_value): + """ Delete the key-value pair in the database """ + if primary_value in self.db['database'][table_name]: + del self.db['database'][table_name][primary_value] + self.dump_db() + self.logger.info(f"Deleted {primary_value} from {table_name}") + return True + return False + + def update(self, table_name, primary_value, value): + """ Update the key-value pair in the database """ + if primary_value in self.db['database'][table_name]: + self.db['database'][table_name][primary_value] = value + self.dump_db() + self.logger.info(f"Updated {primary_value} in {table_name}") + return True + return False + + def search(self, table_name, primary_value): + """ Search the key-value pair in the database """ + if primary_value in self.db['database'][table_name]: + return self.db['database'][table_name][primary_value] + return False + + def where(self, table_name, column_name, value): + """ Search the key-value pair in the database """ + result = [] + for key, val in self.db['database'][table_name].items(): + if val[column_name] == value: + result.append(val) + return result + + def __repr__(self): + return f"QuickDB(db_path={self.db_path}, db={self.db})" + + def __str__(self): + return f"QuickDB(db_path={self.db_path}, db={self.db})" diff --git a/quickdb_/cli.py b/quickdb_/cli.py deleted file mode 100644 index 4d2e254..0000000 --- a/quickdb_/cli.py +++ /dev/null @@ -1,3 +0,0 @@ -from quickdb.main import QuickDB -import argparse - diff --git a/quickdb_/main.py b/quickdb_/main.py deleted file mode 100644 index ed01209..0000000 --- a/quickdb_/main.py +++ /dev/null @@ -1,90 +0,0 @@ -import os -import json - -from colorama import Fore, Style - - -def print_it(color, text): - if color == "red": - print(Fore.RED + text + Style.RESET_ALL) - elif color == "green": - print(Fore.GREEN + text + Style.RESET_ALL) - elif color == 'blue': - print(Fore.BLUE + text + Style.RESET_ALL) - - -class QuickDB(object): - """ python database.py """ - def __init__(self, db_path, overwrite_db=False): - self.db_path = db_path - self.db = self.__init_db(overwrite_db) - - def __load_db_from_file(self): - with open(self.db_path, 'r') as f: - return json.load(f) - - def __init_db(self, overwrite_db): - if not overwrite_db and os.path.exists(self.db_path): - print_it("green", "Loading database from file") - return self.__load_db_from_file() - - elif overwrite_db and os.path.exists(self.db_path): - print_it("blue", "Overwriting database") - self.clear() - return self.db - - elif not os.path.exists(self.db_path): - print_it("green", "Creating new database") - return {} - - def __dump_db(self, data): - try: - with open(self.db_path, 'w+') as f: - json.dump(data, f, indent=4) - return True - except Exception as e: - return False - - def set(self, key, value, overwrite=False): - if key not in self.db: - print_it("green", "Key is not present in the database, adding in the database") - - self.db[key] = value - self.__dump_db(self.db) - return True - - elif not overwrite and key in self.db: - print_it("red", "Key already exists") - return False - - elif overwrite and key in self.db: - print_it("blue", "Key already exists, overwriting the value") - self.db[key] = value - self.__dump_db(self.db) - return True - - def get(self, key): - if key in self.db: - return self.db[key] - else: - print_it("red", "Key not found") - return False - - def delete(self, key): - if key in self.db: - del self.db[key] - self.__dump_db(self.db) - print_it("green", "Key deleted") - else: - print_it("red", "Key not found") - - def get_db(self): - print(self.db) - return self.db - - def clear(self): - self.db = {} - self.__dump_db(self.db) - print_it("green", "Database cleared") - return True - diff --git a/quickdb_/tests/test_cases.py b/quickdb_/tests/test_cases.py deleted file mode 100644 index 36e4f0d..0000000 --- a/quickdb_/tests/test_cases.py +++ /dev/null @@ -1,34 +0,0 @@ -import sys -sys.path.append('.') -import unittest - -from quickdb.main import QuickDB - -db = QuickDB("test_db.json", overwrite_db=True) - -class DatabaseTest(unittest.TestCase): - - def test_operation_one(self): - """ if key does not exist, it should be added """ - self.assertTrue(db.set("name", "john")) - self.assertTrue(db.set("age", 25)) - self.assertTrue(db.set("age", 30, overwrite=True)) - self.assertEqual(db.get_db(), {'name': 'john', 'age': 30}) - self.assertTrue(db.clear(), True) - - def test_operation_two(self): - """ if key already exists, it should not be added """ - self.assertTrue(db.set("name", "john")) - self.assertFalse(db.set("name", "john")) - self.assertTrue(db.clear(), True) - - def test_operation_three(self): - """ if key already exists, it should be overwritten """ - self.assertTrue(db.set("name", "john")) - self.assertTrue(db.set("name", "john", overwrite=True)) - self.assertTrue(db.clear(), True) - - - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index bad478a..eb83bf7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -colorama +pandas pytest flake8 \ No newline at end of file diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..e8fe103 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,11 @@ +# Scripts + +1. test_changes.sh - Test if the changes are valid and can be released. flake8/pytest are run and the version is checked. +2. code_coverage.sh - Run the tests and generate a code coverage report. +3. test_release.sh - Test the release on test.pypi.org. +4. release.sh - Release the package to PyPI if both tests are successful. + + +reference links: + +- https://packaging.python.org/en/latest/guides/using-testpypi/ diff --git a/scripts/code_coverage.sh b/scripts/code_coverage.sh new file mode 100644 index 0000000..1ad60ee --- /dev/null +++ b/scripts/code_coverage.sh @@ -0,0 +1,17 @@ +#!/bin/bash +check_command() { + if [ ! -x "$(command -v $1)" ]; then + echo "$1 is not installed" + pip install $1 + exit 1 + fi +} + +check_command coverage +check_command pytest + +coverage run -m pytest +coverage report -> coverage.txt + + + diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100644 index 0000000..7d7fc54 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,36 @@ +#!/bin/bash +check_command() { + if [ ! -x "$(command -v $1)" ]; then + echo "$1 is not installed" + pip install $1 + exit 1 + fi +} + +check_directory() { + if [ ! -d "$1" ]; then + echo "$1 is not found" + exit 1 + fi +} + +check_file() { + if [ ! -f "$1" ]; then + echo "$1 is not found" + exit 1 + fi +} + +# check if the git is installed +check_command git +check_command flake8 +check_command twine +check_file setup.py +python3 setup.py sdist bdist_wheel +check_directory dist +python3 -m twine upload dist/* + +rm -rf dist +rm -rf build +rm -rf *.egg-info +find . -name "*.pyc" -exec rm -rf {}\; diff --git a/scripts/test_changes.sh b/scripts/test_changes.sh new file mode 100644 index 0000000..565a414 --- /dev/null +++ b/scripts/test_changes.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# function to check the command exist or not +check_command() { + if [ ! -x "$(command -v $1)" ]; then + echo "$1 is not installed" + pip install $1 + exit 1 + fi +} + +# check if the git is installed +check_command git +check_command pytest +check_command flake8 + +flake8 . --isolated --exclude=.cache,.venv,.svn,CVS,.bzr,.hg,.git,__pycache__,.tox,**/migrations/** --ignore=E501,E402 +pytest + +# check the exit code of the last command +if [ $? -eq 0 ]; then + echo "All tests passed" +else + echo "Some tests failed" + exit 1 +fi + diff --git a/scripts/test_release.sh b/scripts/test_release.sh new file mode 100644 index 0000000..58e8161 --- /dev/null +++ b/scripts/test_release.sh @@ -0,0 +1,36 @@ +#!/bin/bash +check_command() { + if [ ! -x "$(command -v $1)" ]; then + echo "$1 is not installed" + pip install $1 + exit 1 + fi +} + +check_directory() { + if [ ! -d "$1" ]; then + echo "$1 is not found" + exit 1 + fi +} + +check_file() { + if [ ! -f "$1" ]; then + echo "$1 is not found" + exit 1 + fi +} + +# check if the git is installed +check_command git +check_command flake8 +check_command twine +check_file ./setup.py +python setup.py sdist bdist_wheel +check_directory dist +python -m twine upload --repository testpypi dist/* + +rm -rf dist +rm -rf build +rm -rf *.egg-info +find . -name "*.pyc" -exec rm -rf {}\; diff --git a/setup.py b/setup.py index 2a848a7..d2fb7eb 100644 --- a/setup.py +++ b/setup.py @@ -4,8 +4,8 @@ long_description = fh.read() setuptools.setup( - name="quickDB", - version="0.0.1", + name="quickDatabase", + version="0.0.5", author="Deepak Raj", author_email="deepak008@live.com", description="Simple python database", @@ -24,6 +24,6 @@ ], python_requires=">=3.4", entry_points={ - "console_scripts": [], + "console_scripts": ["quickdb=quickdb.cli:main"] }, ) diff --git a/test.py b/test.py deleted file mode 100644 index e4ac932..0000000 --- a/test.py +++ /dev/null @@ -1,10 +0,0 @@ -from quickdb.main import QuickDB - -db = QuickDB("test_db.json", overwrite_db=True) -db.set("name", "John") -db.set("age", 25) -db.set("age", 30, overwrite=True) -print(db.get("name")) -print(db.get("age")) - -db.get_db() \ No newline at end of file diff --git a/tests/test_cases.py b/tests/test_cases.py new file mode 100644 index 0000000..b640704 --- /dev/null +++ b/tests/test_cases.py @@ -0,0 +1,56 @@ +import unittest +import sys + +sys.path.append(".") + +from quickdb.main import QuickDB +db = QuickDB("test_db.json", overwrite_db=True) + + +class DatabaseTest(unittest.TestCase): + + def test_create_table(self): + table_name = 'employee' + columns = ['serial', 'name', 'age', 'city', 'country', 'email', 'phone', 'salary'] + primary_key = 'serial' + db.create_table(table_name, columns, primary_key) + self.assertEqual(db.get_table_columns(table_name), columns) + + def test_get_table_names(self): + table_name = 'employee' + self.assertEqual(db.get_table_names(), [table_name]) + + def test_get_table(self): + table_name = 'employee' + columns = ['serial', 'name', 'age', 'city', 'country', 'email', 'phone', 'salary'] + primary_key = 'serial' + self.assertEqual(db.get_table(table_name), {"columns_list": columns, + "primary_key": primary_key, + "primary_key_index": 0}) + + def test_get_table_primary_key(self): + table_name = 'employee' + primary_key = 'serial' + self.assertEqual(db.get_table_primary_key(table_name), primary_key) + + def test_insert_into(self): + table_name = 'employee' + db.insert_into(table_name=table_name, + value=[1, 'John Doe', 30, 'New York', 'USA', 'd@mail.com', '1234567890', 50000], commit=True) + self.assertEqual(len(db.get_table_data(table_name)), 1) + + def test_drop_table(self): + table_name = 'student' + columns = ['roll', 'name', 'age', 'city', 'country', 'email', 'phone', 'fees'] + primary_key = 'roll' + db.create_table(table_name, columns, primary_key) + self.assertEqual(db.get_table_names(), ['employee', 'student']) + db.drop_table(table_name) + self.assertEqual(db.get_table_names(), ['employee']) + + def test_clear_database(self): + db.clear_database() + self.assertEqual(db.get_db(), {"database": {}, "schema": {}}) + +if __name__ == '__main__': + unittest.main() diff --git a/tmp.py b/tmp.py new file mode 100644 index 0000000..e69de29