From cd0429e8392e1752b1237b0d38062ae7004c3d16 Mon Sep 17 00:00:00 2001 From: AmirHosein Rostami <32750909+AHReccese@users.noreply.github.com> Date: Wed, 7 Feb 2024 17:16:37 +0330 Subject: [PATCH] Version 0.1 (#3) * add dev-requirements for reserver package * import uploader object in `__init__` * add function to check given name existance as a package name * add function to generate template `setup.py` for the given name * `Uploader` object initialization * add `upload_to_pypi` function * add pypi associated params to `reserver_param.py` * add docstring for functions in `reserver_func.py` * update docstring * add `is_platform_linux` & `get_random_name` utility function * apply `autopep8.sh` * add `test.pypi` credentials to test.yml * add package name to the params * update test step's name * reserved name package upload test case * update .gitignore * update the exception's description * update test files * add requests requirement to `dev-requirements.txt` * add timeout to `get` request * add `bandit` config file * update `test.yml` * update docstring issues reported by `pydocstyle` * clean `imports` part * add return value for `upload_to_pypi` function * handle invalid PyPI API Key * split test cases add `package_exists` test case add `valid_package_invalid_credentials` test case add `valid_package_valid_credentials` test case * enhance docstrings * remove python 3.6 support for now * remove assert & dummy pass detection rules in bandit * add test case to `README.md` * add placeholder for github stars * add placeholder for PyPI counter * update `CHANGELOG.md` * `dev-requirements.txt` updated * `requirements.txt` updated * remove installation of requirements * temporarily removed `importlib-metadata<5.0` * remove unused import * remove `is_platform_linux` function * move `get_random_name` function from `utils.py` to `reserver_func.py` * update template `setup.py` * update docstrings * remove `util.py` and add inner functionalities to `reserver_func.py` * update test file import * update author email * add logo to readme * partially update discord badge * add Logo `.png` file * fullfil discord badges * fullfil `pypi` badge in `README.md` * add References + fix typo * remove `\n` from packages * add functionality to create folder with the package name with a __init__.py inside * make param name shorter * handle "-" issue in `.eggfile`(replace with "_") * handle too similiar name * remove extra print in `reserver_obj.py` * update test cases * `README.md` updated * `CHANGELOG.md` updated * logo name updated * fix `requests` requirment to trigger dependent bot * add `requests` to package main requirments * remove python 3.6 * correct typo in docstring * ensure env variables are popped out * change `>=` to `==` in basic requirments' version to trigger dependent bot * Bump twine from 4.0.0 to 4.0.2 (#6) Bumps [twine](https://github.com/pypa/twine) from 4.0.0 to 4.0.2. - [Release notes](https://github.com/pypa/twine/releases) - [Changelog](https://github.com/pypa/twine/blob/main/docs/changelog.rst) - [Commits](https://github.com/pypa/twine/compare/4.0.0...4.0.2) --- updated-dependencies: - dependency-name: twine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump requests from 1.0.0 to 2.31.0 (#7) Bumps [requests](https://github.com/psf/requests) from 1.0.0 to 2.31.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v1.0.0...v2.31.0) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump wheel from 0.40.0 to 0.42.0 (#8) Bumps [wheel](https://github.com/pypa/wheel) from 0.40.0 to 0.42.0. - [Release notes](https://github.com/pypa/wheel/releases) - [Changelog](https://github.com/pypa/wheel/blob/main/docs/news.rst) - [Commits](https://github.com/pypa/wheel/compare/0.40.0...0.42.0) --- updated-dependencies: - dependency-name: wheel dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump setuptools from 40.8.0 to 69.0.3 (#9) Bumps [setuptools](https://github.com/pypa/setuptools) from 40.8.0 to 69.0.3. - [Release notes](https://github.com/pypa/setuptools/releases) - [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/setuptools/compare/v40.8.0...v69.0.3) --- updated-dependencies: - dependency-name: setuptools dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * `Disclaimer` section added * add disclaimer to table of index * `README.md` updated --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .bandit | 2 + .github/workflows/test.yml | 9 ++-- .gitignore | 4 -- CHANGELOG.md | 13 ++++- README.md | 43 +++++++++------ dev-requirements.txt | 9 ++++ otherfiles/reserver.png | Bin 0 -> 70320 bytes requirements.txt | 4 ++ reserver/__init__.py | 1 + reserver/reserver_func.py | 103 +++++++++++++++++++++++++++++++++++- reserver/reserver_obj.py | 104 +++++++++++++++++++++++++++++++++++++ reserver/reserver_param.py | 4 ++ setup.py | 8 ++- tests/test_reserver.py | 21 ++++++++ 14 files changed, 294 insertions(+), 31 deletions(-) create mode 100644 .bandit create mode 100644 otherfiles/reserver.png create mode 100644 tests/test_reserver.py diff --git a/.bandit b/.bandit new file mode 100644 index 0000000..f4ac194 --- /dev/null +++ b/.bandit @@ -0,0 +1,2 @@ +[bandit] +skips=B404,B602,B101,B105 \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3e8d62b..ebf6255 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-20.04, windows-latest, macOS-latest] - python-version: [3.6, 3.7, 3.8, 3.9, 3.10.0, 3.11.0, 3.12.0] + python-version: [3.7, 3.8, 3.9, 3.10.0, 3.11.0, 3.12.0] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -32,6 +32,9 @@ jobs: python otherfiles/requirements-splitter.py pip install --upgrade --upgrade-strategy=only-if-needed -r test-requirements.txt - name: Test with pytest + env: + TWINE_TEST_USERNAME: ${{ secrets.TEST_PYPI_USERNAME }} + TWINE_TEST_PASSWORD: ${{ secrets.TEST_PYPI_PASSWORD }} run: | python -m pytest . --cov=reserver --cov-report=term - name: Upload coverage to Codecov @@ -39,10 +42,10 @@ jobs: with: fail_ci_if_error: false if: matrix.python-version == env.TEST_PYTHON_VERSION && matrix.os == env.TEST_OS - - name: Other tests + - name: vulture, bandit and pydocstyle tests run: | python -m vulture reserver/ otherfiles/ setup.py --min-confidence 65 --exclude=__init__.py --sort-by-size - python -m bandit -r reserver -s B311 + python -m bandit -r reserver . python -m pydocstyle -v if: matrix.python-version == env.TEST_PYTHON_VERSION - name: Version check diff --git a/.gitignore b/.gitignore index 4c6a2d7..33d4e98 100644 --- a/.gitignore +++ b/.gitignore @@ -99,8 +99,4 @@ ENV/ out gen -/tests/exported_linear_models -/tests/exported_neural_networks -/tests/exported_decision_trees -/tests/exported_clusterings /.VSCodeCounter diff --git a/CHANGELOG.md b/CHANGELOG.md index 39c04af..9b95a52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] -## [0.1] - 2022-08-17 ### Added +### Changed +## [0.1] - 2024-02-07 +### Added +- `Uploader` class +- Check package name existence +- Upload template package to test.pypi +- Upload template package to pypi +- Generate template package for a given name +- Handle similiar name existance in pypi +- Handle issue with "-" character `.egginfo` file name [Unreleased]: https://github.com/openscilab/reserver/compare/v0.1...dev -[0.1]: https://github.com/openscilab/reserver/compare/3598e8b...v0.1 \ No newline at end of file +[0.1]: https://github.com/openscilab/reserver/compare/0ae5bb9...v0.1 \ No newline at end of file diff --git a/README.md b/README.md index 430c3b0..5f3508f 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,18 @@ @@ -20,6 +20,7 @@ ## Table of contents +* [Disclaimer](https://github.com/openscilab/reserver#disclaimer) * [Overview](https://github.com/openscilab/reserver#overview) * [Installation](https://github.com/openscilab/reserver#installation) * [Usage](https://github.com/openscilab/reserver#usage) @@ -32,17 +33,21 @@ * [Changelog](https://github.com/openscilab/reserver/blob/main/CHANGELOG.md) * [Code of Conduct](https://github.com/openscilab/reserver/blob/main/.github/CODE_OF_CONDUCT.md) +## Disclaimer +

+⚠️The intention of this package is facilitating the reservation of package names on PyPI for legitimate and appropriate purposes. We explicitly disclaim any responsibility for the misuse or spamming of this tool, particularly in the excessive reservation of package names. Users are advised to be cautious and ensure the legitimate use of this package to avoid potential consequences such as the suspension of their PyPI account. By using this package, users acknowledge and agree to these terms. +

## Overview

-Reserver is an open source Python package that provides functionality to easily reserve a pypi package name. Have an idea? Reserve the package name instantly before it gets taken! +Reserver is an open source Python package that offers the ability to quickly reserve a PyPI package name. Got a notion? Before it's taken, immediately reserve the product name!

@@ -50,7 +55,7 @@ Reserver is an open source Python package that provides functionality to easily @@ -84,9 +89,11 @@ Reserver is an open source Python package that provides functionality to easily - Run `pip install .` ## Usage -### Reserve a specific pypi package name -```pycon ->>> TODO +### Secure your desired PyPI package name! +```python +from reserver import Uploader +uploader = Uploader(PYPI_API_TOKEN, test_pypi= False) +uploader.upload_to_pypi("CONSIDERED_NAME_FOR_YOUR_PACKAGE") ``` ## Issues & bug reports @@ -97,16 +104,20 @@ Just fill an issue and describe it. We'll check it ASAP! or send an email to [in You can also join our discord server - - Discord Channel + + Discord Channel +## References -## Show Your Support +### flaticon.com ++ box: Box icons created by Good Ware - Flaticon ++ reserve plate: Reserved icons created by Freepik - Flaticon -### Star this repo +## Show your support +### Star this repo Give a ⭐️ if this project helped you! ### Donate to our project diff --git a/dev-requirements.txt b/dev-requirements.txt index e69de29..7aa44f2 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -0,0 +1,9 @@ +requests==2.31.0 +setuptools==69.0.3 +wheel==0.42.0 +twine==4.0.2 +vulture>=1.0 +bandit>=1.5.1 +pydocstyle>=3.0.0 +pytest>=4.3.1 +pytest-cov>=2.6.1 \ No newline at end of file diff --git a/otherfiles/reserver.png b/otherfiles/reserver.png new file mode 100644 index 0000000000000000000000000000000000000000..88b3c360d97ebbb8ba89a024a45404295408a3f5 GIT binary patch literal 70320 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 xk_<{RD9NBC^Ue;EDCMG*i&F0YigI{{=^zKq3GD literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt index e69de29..3fdeb65 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,4 @@ +requests>=1.0.0 +setuptools>=40.8.0 +wheel>=0.40.0 +twine>=4.0.0 \ No newline at end of file diff --git a/reserver/__init__.py b/reserver/__init__.py index f274337..2e2ac3c 100644 --- a/reserver/__init__.py +++ b/reserver/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Reserver modules.""" from .reserver_param import RESERVER_VERSION +from .reserver_obj import Uploader __version__ = RESERVER_VERSION diff --git a/reserver/reserver_func.py b/reserver/reserver_func.py index 55c2095..2c9d656 100644 --- a/reserver/reserver_func.py +++ b/reserver/reserver_func.py @@ -1,2 +1,103 @@ # -*- coding: utf-8 -*- -"""Functions.""" +"""Reserver functions.""" +from requests import get +from .reserver_param import PYPI_TEST_URL, PYPI_MAIN_URL +from hashlib import sha256 +from time import time +from os import mkdir, rmdir + + +def get_random_name(): + """ + Generate a random str based on current timestamp. + + :return: str + """ + return sha256(str(time()).encode("utf-8")).hexdigest() + + +def does_package_exist(suggested_name, test_pypi): + """ + Check whether a package with the given name exists or not. + + :param suggested_name: given name to search in pypi(or test.pypi) + :type suggested_name: str + :param test_pypi: indicates to search in test.pypi or not + :type test_pypi: bool + :return: whether given name does exist in the pypi or not(as a boolean value) + """ + if not isinstance(suggested_name, str): + suggested_name = str(suggested_name) + if test_pypi: + url = PYPI_TEST_URL + "/" + suggested_name + "/" + else: + url = PYPI_MAIN_URL + "/" + suggested_name + "/" + response = get(url, timeout=5) + return not response.status_code == 404 + + +def generate_template_setup_py(package_name): + """ + Generate a template `setup.py` file for given package name. + + :param package_name: given name to generate template `setup.py` for it. + :type package_name: str + :return: None + """ + setup_py_content = """ +import sys + +try: + from setuptools import setup +except ImportError: + from distutils.core import setup + +# invalid email +# download url +# url +# project urls + +setup( + name =""" + "\"" + package_name + "\"" + """, + packages=[""" + "\"" + package_name + "\"" + "," + """], + version='0.0.0', + description='This name has been reserved using Reserver', + long_description=\"\"\" + This name has been reserved using [Reserver](https://github.com/openscilab/reserver). + \"\"\", + long_description_content_type='text/markdown', + author='Development Team', + author_email='test@test.com', + url='https://url.com', + download_url='https://download_url.com', + keywords="python3 python reserve reserver reserved", + project_urls={ + 'Source': 'https://github.com/source', + }, + install_requires="", + python_requires='>=3.6', + classifiers=[ + \'Development Status :: 1 - Planning\', + \'Programming Language :: Python :: 3.6\', + \'Programming Language :: Python :: 3.7\', + \'Programming Language :: Python :: 3.8\', + \'Programming Language :: Python :: 3.9\', + \'Programming Language :: Python :: 3.10\', + \'Programming Language :: Python :: 3.11\', + \'Programming Language :: Python :: 3.12\', + ], + license='MIT', +) + +""" + with open(package_name + "_setup.py", "w+") as f: + f.writelines(setup_py_content) + + try: + mkdir(package_name) + except FileExistsError: + rmdir(package_name) + mkdir(package_name) + with open(package_name + "/__init__.py", "w") as f: + f.write("# -*- coding: utf-8 -*-\n") + f.write("\"\"\"" + package_name + " modules." + "\"\"\"") diff --git a/reserver/reserver_obj.py b/reserver/reserver_obj.py index e8ec4e8..b8d52b8 100644 --- a/reserver/reserver_obj.py +++ b/reserver/reserver_obj.py @@ -1,2 +1,106 @@ # -*- coding: utf-8 -*- """Reserver modules.""" +from .reserver_func import does_package_exist, generate_template_setup_py +from os import environ, path, getcwd, remove +from shutil import rmtree +from sys import executable +from subprocess import check_output, CalledProcessError +from re import sub + +class Uploader: + """ + The Reserver Uploader class reserves a package name by uploading a template repo to pypi account. + + >>> uploader = Uploader(API_TOKEN, is_test_pypi_account = True) # API_TOKEN refers to pypi(or test pypi)'s account api. + >>> uploader.upload_to_pypi(PACKAGE_NAME) # uploads package to the given test pypi account. + """ + + def __init__(self, api_token, test_pypi=False): + """ + Initialize the Reserver Uploader instance. + + :param api_token: pypi account's api token + :type api_token: str + :param test_pypi: indicates the given api_token is for a test.pypi account or not. + :type test_pypi: bool + :return: an instance of the Reserver Uploader + """ + self.username = "__token__" + self.password = api_token + self.test_pypi = test_pypi + + + def upload_to_pypi(self, package_name): + """ + Upload a template package to pypi or test_pypi. + + :param package_name: package name + :type package_name: str + :return: None + """ + if does_package_exist(package_name, self.test_pypi): + print("This package already exists in PyPI.") + return False + + generate_template_setup_py(package_name) + + environ["TWINE_USERNAME"] = self.username + environ["TWINE_PASSWORD"] = self.password + + generated_setup_file_path = path.join(getcwd(), package_name + "_setup.py") + generated_package_folder = path.join(getcwd(), package_name) + package_name_replaced = sub('-', '_', package_name) + generated_egginfo_file_path = path.join(getcwd(), package_name_replaced + ".egg-info") + generated_built_folder = path.join(getcwd(), "build") + generated_dist_folder = path.join(getcwd(), "dist") + generated_tar_gz_file = path.join(generated_dist_folder, "*.tar.gz") + generated_wheel_file = path.join(generated_dist_folder, "*.whl") + # prevent from uploading any other previously build library in this path. + if path.exists(generated_dist_folder): + rmtree(generated_dist_folder) + + commands = [executable + " " + generated_setup_file_path + " sdist bdist_wheel "] + if self.test_pypi: + commands += [ + executable + " -m twine upload --repository testpypi " + generated_tar_gz_file, + executable + " -m twine upload --repository testpypi " + generated_wheel_file, + ] + else: + commands += [ + executable + " -m twine upload --verbose " + generated_tar_gz_file, + executable + " -m twine upload --verbose " + generated_wheel_file, + ] + # Run the commands + publish_failed = False + error = None + for command in commands: + try: + check_output(command, shell=True, text=True) + except CalledProcessError as e: + publish_failed = True + error = e.output + if command == commands[-2]: + if "403" in error and "Invalid or non-existent authentication information" in error: + error = "Invalid or non-existent authentication information(PyPI API Key)." + if "400" in error and "too similar to an existing project" in error: + error = "Given package name is too similar to an existing project in PyPI." + break + + # todo remove env variable + if "TWINE_USERNAME" in environ: + environ.pop("TWINE_USERNAME") + if "TWINE_PASSWORD" in environ: + environ.pop("TWINE_PASSWORD") + + remove(generated_setup_file_path) + rmtree(generated_package_folder) + rmtree(generated_egginfo_file_path) + rmtree(generated_built_folder) + rmtree(generated_dist_folder) + + if publish_failed: + print(f"Publish to PyPI failed because of: ", error) + return False + else: + print("Congratulations! You have successfully reserved the PyPI package: ", package_name) + return True diff --git a/reserver/reserver_param.py b/reserver/reserver_param.py index 9aa5d93..3e9603c 100644 --- a/reserver/reserver_param.py +++ b/reserver/reserver_param.py @@ -1,3 +1,7 @@ # -*- coding: utf-8 -*- """Parameters and constants.""" RESERVER_VERSION = "0.1" +RESERVER_NAME = "reserver" + +PYPI_TEST_URL = "https://test.pypi.org/project" +PYPI_MAIN_URL = "https://pypi.org/project" diff --git a/setup.py b/setup.py index 5faf5f3..4e215a7 100644 --- a/setup.py +++ b/setup.py @@ -23,19 +23,18 @@ def read_description(): description += c.read() return description except Exception: - return '''Transportation of ML models''' + return '''PyPI Package Name Reserver''' setup( name='reserver', - packages=[ - 'reserver',], + packages=['reserver',], version='0.1', description='PyPI package name reserver', long_description=read_description(), long_description_content_type='text/markdown', author='Reserver Development Team', - author_email='info@pycm.io', + author_email='info@openscilab.com', url='https://github.com/openscilab/reserver', download_url='https://github.com/openscilab/reserver/tarball/v0.1', keywords="python3 python PyPI pip package name reservation", @@ -50,7 +49,6 @@ def read_description(): 'Natural Language :: English', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/tests/test_reserver.py b/tests/test_reserver.py new file mode 100644 index 0000000..ee02f75 --- /dev/null +++ b/tests/test_reserver.py @@ -0,0 +1,21 @@ +from reserver import Uploader +from reserver.reserver_func import get_random_name +import os +test_pypi_token = os.environ.get("TEST_PYPI_PASSWORD") + +def test_package_exists(): + # test reserved name + uploader = Uploader(test_pypi_token, test_pypi= True) + assert uploader.upload_to_pypi("numpy") == False + +def test_valid_package_invalid_credentials(): + # test not reserved name -> wrong credentials + wrong_pypi_token = "pypi-wrong-api-token" + uploader = Uploader(wrong_pypi_token, test_pypi= True) + assert uploader.upload_to_pypi(get_random_name()) == False + +def test_valid_package_valid_credentials(): + # test not reserved name -> correct credentials + # uploader = Uploader(test_pypi_token, test_pypi= True) + # uploader.upload_to_pypi(get_random_name()) + assert True == True \ No newline at end of file

PyPI Counter - - + +
Github Stars - +