diff --git "a/doc/pip\345\256\211\350\243\205\344\270\216\347\211\210\346\234\254\346\233\264\346\226\260.md" "b/doc/pip\345\256\211\350\243\205\344\270\216\347\211\210\346\234\254\346\233\264\346\226\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..edb21171a2554dedf02c2139862fd8a18107435b --- /dev/null +++ "b/doc/pip\345\256\211\350\243\205\344\270\216\347\211\210\346\234\254\346\233\264\346\226\260.md" @@ -0,0 +1,133 @@ + + + + + + +# 应用通过pip进行版本迭代更新 + +难点: + +pip 安装包只会把文件放置在指定目录下。因此,期待用户安装后,可以通过2种方式启动应用。 + +1. 通过python代码启动 + + ```python + import pandas-coder + ``` + +2. 通过命令,在指定目录输出一个bat文件,后续通过bat文件启动 + + + +# 版本检查 + +通过pip检查最新版本号: + +```python +import subprocess +ret = subprocess.run("pip install pandas-coder== -i https://pypi.douban.com/simple/",stdout=subprocess.PIPE, stderr=subprocess.PIPE,shell=True) + +ret = str(ret.stderr) +``` + +这个指令会返回一个如: + +```shell +ERROR: Could not find a version that satisfies the requirement pandas-coder== (from versions: 0.1.0, 0.2.0)\r\nERROR: No matching distribution found for test-myp== +``` + + + +使用正则表达式,提取其中的版本信息即可: + +```python +import re +cp = re.compile(r'\((from versions: (.*?))\)') + +vs = cp.search(ret).groups()[1].split(',') +new_verson = vs[-1] +``` + + + +与当前版本号对比即可知道是否需要更新。 + + + + + +# 更新 + +通过pip 指令更新: + +```python +subprocess.run("pip install pandas-coder -U -i https://pypi.douban.com/simple/",stdout=subprocess.PIPE, stderr=subprocess.PIPE,shell=True) +``` + + + +## 更新时机 + +在工具启动时,做检查与更新吧。 + + + +## 更新频率 + +国内镜像,只有豆瓣能在半小时内同步pip,因此暂时考虑使用他的镜像吧 + + + + + + + +# 发布流程 + + + +```shell +pip install --upgrade setuptools +``` + + + +安装帮助上传的工具 + +```shell +pip install twine +``` + + + +使用模板: + +```shell +git clone https://github.com/kennethreitz/setup.py +``` + + + +修改里面的 setup.py + + + +打包: + +```shell +python setup.py sdist +``` + + + +执行上传: + +```shell +twine upload dist/* +``` + + + + + diff --git a/py/.gitignore b/py/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..58d66aaf93baecfd3b10ea737bc9e26246b609b3 --- /dev/null +++ b/py/.gitignore @@ -0,0 +1,7 @@ + + +**/dist +**/__pycache__ +setup.py/pdcopyist +setup.py/pdcopyist.egg-info + diff --git a/py/__init__.py b/py/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9994628ef9c661c16b92cccd3a0908e2e014a772 --- /dev/null +++ b/py/__init__.py @@ -0,0 +1,3 @@ + + +__version__ = tuple('0.1.2'.split('.')) diff --git a/py/build/build.bat b/py/build/build.bat index af93c97b6134920b47c047df6f429a22125f29da..11193bd1d8a61cd43eb39482f36150ec36aeb3bb 100644 --- a/py/build/build.bat +++ b/py/build/build.bat @@ -1,3 +1,2 @@ -call activate py36 python build.py pause \ No newline at end of file diff --git a/py/build/build.py b/py/build/build.py index b60e059b88f101fff2c8645addd80a013e490d85..74198e956a7eb9b29567730a228712e4362b19db 100644 --- a/py/build/build.py +++ b/py/build/build.py @@ -5,6 +5,8 @@ import shutil import os +pkg_name = 'pdcopyist' + is_compileall = False @@ -14,72 +16,36 @@ vinfo = sys.version_info py_num = f'{vinfo.major}{vinfo.minor}' -m_dist_app_path = plib.Path(f'../dist/app{vinfo.major}{vinfo.minor}') -m_dist_src_path = m_dist_app_path / 'src' -m_dist_web_path = m_dist_app_path / 'web' -m_dist_main_path = m_dist_app_path / 'main.py' -m_dist_startup_path = m_dist_app_path / 'startup.bat' - -if is_compileall: - compileall.compile_dir(r'../src') - compileall.compile_file('../main.py') - print('编译完毕') - -if os.path.exists(m_dist_app_path): - shutil.rmtree(m_dist_app_path) - -os.makedirs(m_dist_app_path) - -print('清除旧文件完毕') - - -def to_fileName(file: plib.Path): - arr = file.name.split('.') - return '.'.join([arr[0], arr[1]]) +m_target_path = plib.Path(f'../setup.py/{pkg_name}') +m_src_path = plib.Path(f'../src') +m_target_src_path = m_target_path / 'src' -def to_folder(file: plib.Path): - parts = list(file.parts) - # del parts[-2] - parts[-1] = to_fileName(file) +m_web_path = plib.Path(f'../web') +m_target_web_path = m_target_path / 'web' - parts = [p for p in parts if not all(s in ['.', '/'] for s in p)] +m_main_path = plib.Path(f'../main.py') +m_target_main_path = m_target_path / 'main.py' - parts = plib.Path.joinpath(m_dist_app_path, *parts) - return parts +m_init_path = plib.Path(f'../__init__.py') +m_target_init_path = m_target_path / '__init__.py' +m_other_path = plib.Path(f'others') +# m_target_other_path = m_target_path / 'startup_win.bat' -if is_compileall: - fs = plib.Path('../src').rglob(f'*.cpython-{py_num}.pyc') - fs = [(p, to_folder(p)) for p in fs] - - for f in fs: - if not os.path.exists(f[1].parent): - os.makedirs(f[1].parent) - - shutil.copyfile(f[0], f[1]) - - shutil.copyfile( - f'../__pycache__/main.cpython-{py_num}.pyc', m_dist_main_path) - -else: - fs = plib.Path('../src').rglob(f'*.py') - fs = [(p, to_folder(p)) for p in fs] - - for f in fs: - if not os.path.exists(f[1].parent): - os.makedirs(f[1].parent) - - shutil.copyfile(f[0], f[1]) - - shutil.copyfile(f'../main.py', m_dist_main_path) +# 清空目录 +shutil.rmtree(m_target_path, ignore_errors=True) +os.makedirs(m_target_path) +print('清除旧文件完毕') -shutil.copytree('../web', m_dist_web_path) +shutil.copytree(m_src_path, m_target_src_path) +shutil.copytree(m_web_path, m_target_web_path) +shutil.copyfile(m_main_path, m_target_main_path) +shutil.copyfile(m_init_path, m_target_init_path) -for f in plib.Path('others').glob('*'): - shutil.copyfile(f, m_dist_app_path / f.name) -# shutil.copyfile('../startup.bat', m_dist_startup_path) +for f in m_other_path.glob('*.*'): + shutil.copyfile(f, m_target_path/f.name) -print(f'创建完成-({vinfo})') +print(f'创建完成') diff --git a/py/build/others/startup_linux.sh b/py/build/others/startup_linux.sh index 7a84f979de9940293ba467a8e1c109dc6c70485e..274464a60ae421b2bb22142147314b2896246fb1 100644 --- a/py/build/others/startup_linux.sh +++ b/py/build/others/startup_linux.sh @@ -1 +1 @@ -python main.py \ No newline at end of file +pdcopyist_updater \ No newline at end of file diff --git a/py/build/others/startup_win.bat b/py/build/others/startup_win.bat index bc9d4b248a7bdbb0537d1f1c6cb02b9f648a7620..232d02b904b89f29bc2cf0a9d4467f2f31cc3554 100644 --- a/py/build/others/startup_win.bat +++ b/py/build/others/startup_win.bat @@ -1,2 +1,2 @@ -python main.py +pdcopyist_updater pause \ No newline at end of file diff --git "a/py/build/others/\347\263\273\347\273\237\350\246\201\346\261\202.txt" "b/py/build/others/\347\263\273\347\273\237\350\246\201\346\261\202.txt" deleted file mode 100644 index 418acde7bbeb31b081eb0fb376ec97839d31aacd..0000000000000000000000000000000000000000 --- "a/py/build/others/\347\263\273\347\273\237\350\246\201\346\261\202.txt" +++ /dev/null @@ -1,16 +0,0 @@ -python 3.6 或以上 - -python 必需的库: -- flask -- pandas -- openpyxl(加载excel 2007 或以上版本所需) -- xlrd(加载excel 2003 版本所需) -- feather (feather 格式所需) -- webbrowser(应该是py内置的库) - -执行如下语句安装(使用了国内镜像): -pip install pandas flask xlrd openpyxl -i https://mirrors.aliyun.com/pypi/simple/ - - -浏览器要求: -基本上市面上的主流浏览器都支持,IE就不考虑了 \ No newline at end of file diff --git a/py/main.py b/py/main.py index af7c4af1ec3e10ada8ca5312747fd341e85ba261..888813d3333578ad69d436c17f62d4b58272379f 100644 --- a/py/main.py +++ b/py/main.py @@ -1,3 +1,4 @@ +from typing import Tuple from flask import Flask import flask from flask import request @@ -6,18 +7,21 @@ import numpy as np import json import traceback import sys -from src.cusFuns.core.FunsPool import auto_register -from src.helper.utils import json_converter -from src.dataModel.pandasCmd import PandasCmd -from src.core.Proxy import ProxyManager + +from .src.cusFuns.core.FunsPool import auto_register +from .src.helper.utils import json_converter +from .src.dataModel.pandasCmd import PandasCmd +from .src.core.Proxy import ProxyManager import webbrowser import os +import pathlib +base_path = pathlib.Path(__file__).parent m_proxys = ProxyManager() -auto_register(r'src/cusFuns') +auto_register(base_path, 'src/cusFuns') app = Flask(__name__, template_folder='./web/templates', @@ -46,6 +50,10 @@ def get_data_from_post(): @app.route('/') def index(): + # from . import __version__ + # pd.DataFrame({'a': [1, 2, 3]}).to_csv('test_ret.csv') + # return f'版本号:{__version__}' + return flask.render_template('index.html') @@ -176,6 +184,7 @@ def cus_fun(): @app.route('/api/cus_fun/desc') def get_cus_funcs_desc(): + # auto_register(base_path , 'src/cusFuns') ret = m_proxys.get_cus_funcs_desc() ret = flask.json.dumps(ret, default=json_converter) return ret @@ -200,7 +209,8 @@ def get_cus_funcs_input(): return df2json(m_proxys.get_df_data()) -def main(): +def run(): + port = 5551 # The reloader has not yet run - open the browser @@ -211,5 +221,40 @@ def main(): app.run(host="localhost", port=port) +def find_arg(args, flag, return_value=True): + try: + idx = args.index(flag) + + if return_value: + return True, args[idx+1] + return idx >= 0, None + except ValueError: + pass + + return False, None + + +def copy_bat(): + import pathlib + import shutil + src_path = pathlib.Path(__file__).parent / 'startup_win.bat' + shutil.copyfile(src_path, 'startup_win.bat') + + +def main(): + args = sys.argv + + has, dir = find_arg(args, '-dir') + if has: + os.chdir(dir) + + has, _ = find_arg(args, '-c', return_value=False) + if has: + copy_bat() + return + + run() + + if __name__ == '__main__': main() diff --git a/py/setup.py/.gitignore b/py/setup.py/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7b0eb25be084a9ba5fe0d9c8b93e14c4f6541917 --- /dev/null +++ b/py/setup.py/.gitignore @@ -0,0 +1,91 @@ +# 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 +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject +*.npy +*.pkl diff --git a/py/setup.py/LICENSE b/py/setup.py/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..6cd7b7924ef912ad8804e18ab2efd0c08b64d2e1 --- /dev/null +++ b/py/setup.py/LICENSE @@ -0,0 +1,7 @@ +Copyright + +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. diff --git a/py/setup.py/MANIFEST.in b/py/setup.py/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..4fc9608f0bcdbe48ff566d849bb56501036c425f --- /dev/null +++ b/py/setup.py/MANIFEST.in @@ -0,0 +1,3 @@ +include README.md LICENSE +recursive-include pdcopyist *.* +prune pdcopyist/**/__pycache__ \ No newline at end of file diff --git a/py/setup.py/README.md b/py/setup.py/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d53972bdc5a81f42c5e6aaf160ea6f3422094910 --- /dev/null +++ b/py/setup.py/README.md @@ -0,0 +1,65 @@ +📦 setup.py (for humans) +======================= + +This repo exists to provide [an example setup.py] file, that can be used +to bootstrap your next Python project. It includes some advanced +patterns and best practices for `setup.py`, as well as some +commented–out nice–to–haves. + +For example, this `setup.py` provides a `$ python setup.py upload` +command, which creates a *universal wheel* (and *sdist*) and uploads +your package to [PyPi] using [Twine], without the need for an annoying +`setup.cfg` file. It also creates/uploads a new git tag, automatically. + +In short, `setup.py` files can be daunting to approach, when first +starting out — even Guido has been heard saying, "everyone cargo cults +thems". It's true — so, I want this repo to be the best place to +copy–paste from :) + +[Check out the example!][an example setup.py] + +Installation +----- + +```bash +cd your_project + +# Download the setup.py file: +# download with wget +wget https://raw.githubusercontent.com/navdeep-G/setup.py/master/setup.py -O setup.py + +# download with curl +curl -O https://raw.githubusercontent.com/navdeep-G/setup.py/master/setup.py +``` + +To Do +----- + +- Tests via `$ setup.py test` (if it's concise). + +Pull requests are encouraged! + +More Resources +-------------- + +- [What is setup.py?] on Stack Overflow +- [Official Python Packaging User Guide](https://packaging.python.org) +- [The Hitchhiker's Guide to Packaging] +- [Cookiecutter template for a Python package] + +License +------- + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any means. + + [an example setup.py]: https://github.com/navdeep-G/setup.py/blob/master/setup.py + [PyPi]: https://docs.python.org/3/distutils/packageindex.html + [Twine]: https://pypi.python.org/pypi/twine + [image]: https://farm1.staticflickr.com/628/33173824932_58add34581_k_d.jpg + [What is setup.py?]: https://stackoverflow.com/questions/1471994/what-is-setup-py + [The Hitchhiker's Guide to Packaging]: https://the-hitchhikers-guide-to-packaging.readthedocs.io/en/latest/creation.html + [Cookiecutter template for a Python package]: https://github.com/audreyr/cookiecutter-pypackage diff --git a/py/setup.py/run.py b/py/setup.py/run.py new file mode 100644 index 0000000000000000000000000000000000000000..41e83e70deef4d9a57679bad03f3d4ec594586ab --- /dev/null +++ b/py/setup.py/run.py @@ -0,0 +1,13 @@ + + +import shutil +import os +import pathlib + +os.chdir(pathlib.Path(__file__).parent) + +shutil.rmtree('dist', ignore_errors=True) +os.system('python setup.py sdist') + +# 发布 +os.system('twine upload dist/*') diff --git a/py/setup.py/setup.py b/py/setup.py/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..ae4c325e9de19b235aaf3526d9b8c9fa619042d8 --- /dev/null +++ b/py/setup.py/setup.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Note: To use the 'upload' functionality of this file, you must: +# $ pipenv install twine --dev + +import io +import os +import sys +from shutil import rmtree + +from setuptools import find_packages, setup, Command +from pdcopyist import __version__ + +# Package meta-data. +NAME = 'pdcopyist' +DESCRIPTION = 'A visual data manipulation tool that automatically generates python code' +URL = 'https://gitee.com/carson_add/pandas-ui' +EMAIL = '568166495@qq.com' +AUTHOR = 'Carson Liang' +REQUIRES_PYTHON = '>=3.6.0' +VERSION = '.'.join(__version__) + +# What packages are required for this module to be executed? +REQUIRED = [ + 'pandas', 'pdcopyist_updater', 'flask', 'openpyxl', 'xlrd' +] + +# What packages are optional? +EXTRAS = { + 'pd read feather file': ['feather'], +} + +# The rest you shouldn't have to touch too much :) +# ------------------------------------------------ +# Except, perhaps the License and Trove Classifiers! +# If you do change the License, remember to change the Trove Classifier for that! + +here = os.path.abspath(os.path.dirname(__file__)) + +# Import the README and use it as the long-description. +# Note: this will only work if 'README.md' is present in your MANIFEST.in file! +try: + with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = '\n' + f.read() +except FileNotFoundError: + long_description = DESCRIPTION + +# Load the package's __version__.py module as a dictionary. +about = {} +if not VERSION: + project_slug = NAME.lower().replace("-", "_").replace(" ", "_") + with open(os.path.join(here, project_slug, '__version__.py')) as f: + exec(f.read(), about) +else: + about['__version__'] = VERSION + + +class UploadCommand(Command): + """Support setup.py upload.""" + + description = 'Build and publish the package.' + user_options = [] + + @staticmethod + def status(s): + """Prints things in bold.""" + print('\033[1m{0}\033[0m'.format(s)) + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + try: + self.status('Removing previous builds…') + rmtree(os.path.join(here, 'dist')) + except OSError: + pass + + self.status('Building Source and Wheel (universal) distribution…') + os.system( + '{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) + + self.status('Uploading the package to PyPI via Twine…') + os.system('twine upload dist/*') + + self.status('Pushing git tags…') + os.system('git tag v{0}'.format(about['__version__'])) + os.system('git push --tags') + + sys.exit() + + +# Where the magic happens: +setup( + name=NAME, + version=about['__version__'], + description=DESCRIPTION, + long_description=long_description, + long_description_content_type='text/markdown', + author=AUTHOR, + author_email=EMAIL, + python_requires=REQUIRES_PYTHON, + url=URL, + packages=[NAME], + + entry_points={ + 'console_scripts': [ + f'{NAME} = {NAME}.main:main' + ] + }, + + + # If your package is a single module, use this instead of 'packages': + # py_modules=['mypackage'], + + # entry_points={ + # 'console_scripts': ['mycli=mymodule:cli'], + # }, + + + + install_requires=REQUIRED, + extras_require=EXTRAS, + include_package_data=True, + license='MIT', + classifiers=[ + # Trove classifiers + # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy' + ], + # $ setup.py publish support. + cmdclass={ + 'upload': UploadCommand, + }, +) diff --git a/py/src/__init__.py b/py/src/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/py/src/cusFuns/columnNameChanger/index.py b/py/src/cusFuns/columnNameChanger/index.py index 085c6926bf37dc9f23d1d3be741b7d8ab8adebe5..c1290f5eb108139c83d92dea789e2f1b16000526 100644 --- a/py/src/cusFuns/columnNameChanger/index.py +++ b/py/src/cusFuns/columnNameChanger/index.py @@ -1,3 +1,4 @@ +import importlib from ..core.DecoratorFuns import dt_handle_func, dt_args, dt_source_code from ..core import Args as ty import pandas as pd @@ -12,4 +13,4 @@ def generate_code(*args, **kwargs): @dt_handle_func('修改列名') @dt_args(org_name=ty.ColumnSelect('待修改列:'), new_name=ty.Input('新列名:', placeholder='输入新的列名')) def change_column_name(df, org_name, new_name): - return df.rename(columns={org_name: new_name}) + return df.rename(columns={org_name: new_name}) \ No newline at end of file diff --git a/py/src/cusFuns/core/FunsPool.py b/py/src/cusFuns/core/FunsPool.py index 558f27163ec2ab127709efbd055f94a34b0610ad..86b106aac047d50727f4024dd6f75e7fbfcb774a 100644 --- a/py/src/cusFuns/core/FunsPool.py +++ b/py/src/cusFuns/core/FunsPool.py @@ -1,6 +1,6 @@ -from typing import Callable, Dict +from typing import Callable, Dict, Union import uuid import pathlib import importlib @@ -8,7 +8,7 @@ import inspect import os -from ..core.DecoratorFuns import CusFunsWrapper, HandleWrapper +from .DecoratorFuns import CusFunsWrapper, HandleWrapper from .UIModl import FunModel @@ -97,9 +97,10 @@ class FunsPool(object): def _register_module(module_path: str): ''' module_path : str - 'src.cusFuns.columnNameChanger.columnNameChanger' + 'src.cusFuns.columnNameChanger.index' ''' - module = importlib.import_module(module_path) + pkg = HandleWrapper.__module__.split('.')[0] + module = importlib.import_module(f'.{module_path}', pkg) # [('name',obj)] funcs = [(name, func) for name, func in module.__dict__.items() if isinstance(func, CusFunsWrapper)] @@ -118,12 +119,25 @@ def _register_module(module_path: str): FunsPool.get_once().register(cf) -def auto_register(base_folder: str): - files = (p for p in pathlib.Path(base_folder).glob('*/*.py') - if p.parent.parts[-1] != 'core') +def auto_register(package_path: Union[str, pathlib.PurePath], base_folder: Union[str, pathlib.PurePath]): + org_dir = os.getcwd() - for md_name in files: - md_name = str(md_name)[:-3] - md_name = md_name.replace(os.path.sep, '.') + try: + os.chdir(package_path) + base_folder = pathlib.Path(base_folder) - _register_module(md_name) + files = (p for p in base_folder.glob('*/*.py') + if p.parent.parts[-1] != 'core') + + # print(f'功能池文件:{list(files)}') + + for md_name in files: + md_name = str(md_name)[:-3] + md_name = md_name.replace(os.path.sep, '.') + + _register_module(f'{md_name}') + except Exception: + raise + + finally: + os.chdir(org_dir) diff --git a/py/test.py b/py/test.py index a364b5f6b85e051642bab493c5e3803be2a71ae2..29249ca439fb6942a51a2904e6c5953455da7665 100644 --- a/py/test.py +++ b/py/test.py @@ -1,23 +1,6 @@ - -# %% - -def de_func(title=None): - print(title) - - def wrapper(func): - print(func) - - return wrapper - - # %% -@de_func -def a(x): - """ - docstring - """ - pass - +import pathlib +pathlib.Path('build/build.bat').name # %% diff --git a/py_updater/.gitignore b/py_updater/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..1496bece25381744bb2f7d478e9bacb7fddcc225 --- /dev/null +++ b/py_updater/.gitignore @@ -0,0 +1,7 @@ + + +**/dist +**/__pycache__ +setup.py/pdcopyist_updater +setup.py/pdcopyist_updater.egg-info + diff --git a/py_updater/README.md b/py_updater/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5503eb84d043a1e25745fe5a3a6aae374593aaba --- /dev/null +++ b/py_updater/README.md @@ -0,0 +1,3 @@ +# 为什么需要这个项目 + +此项目旨在启动 pdcoder时自动从pip上更新版本 \ No newline at end of file diff --git a/py_updater/Versions.py b/py_updater/Versions.py new file mode 100644 index 0000000000000000000000000000000000000000..8ae7b71ae78ed193f7ce51b74cfc903a6caae837 --- /dev/null +++ b/py_updater/Versions.py @@ -0,0 +1,41 @@ + +import subprocess +import re +from typing import List, Tuple +from pdcopyist import __version__ + + +class VersionManager(object): + + m_pkg_name = 'pdcopyist' + m_current_version = __version__ + m_version_re = re.compile(r'\((from versions: (.*?))\)') + + def has_updated(self) -> bool: + return self.m_current_version < self.get_last_version() + + def get_versions(self): + ret = self._use_pip(['install', f'{self.m_pkg_name}==']) + ret = str(ret.stderr) + + vs = self.m_version_re.search(ret).groups()[1].split(',') + assert vs[0] != 'none' '未找到任何版本,请检查网络连接' + return [tuple(v.strip().split('.')) for v in vs] + + def get_last_version(self) -> Tuple: + last = self.get_versions()[-1] + return last + + def start_update(self): + # import os + # os.system( + # f'pip install {self.m_pkg_name} -U ') + + self._use_pip(['install', f'{self.m_pkg_name}', '-U']) + + def _use_pip(self, cmds: List[str]): + cmds = ['pip'] + cmds + ['-i', 'https://pypi.douban.com/simple/'] + cmds = ['pip'] + cmds + + return subprocess.run(cmds, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False) diff --git a/py_updater/__init__.py b/py_updater/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/py_updater/main.py b/py_updater/main.py new file mode 100644 index 0000000000000000000000000000000000000000..5c324d5d12038914111e0aff3bb8d69be3729447 --- /dev/null +++ b/py_updater/main.py @@ -0,0 +1,27 @@ + + +import sys +import os +from .Versions import VersionManager + + +def main(): + vm = VersionManager() + if vm.has_updated(): + print(f'发现新版本,开始更新') + vm.start_update() + print(f'更新完成()') + + # args = sys.argv + + # dir = find_arg(args, '-dir') + # if dir: + # os.system(f'pdcoder -dir {dir}') + + os.system(VersionManager.m_pkg_name) + + sys.exit() + + +if __name__ == "__main__": + pass diff --git a/py_updater/setup.py/.gitignore b/py_updater/setup.py/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7b0eb25be084a9ba5fe0d9c8b93e14c4f6541917 --- /dev/null +++ b/py_updater/setup.py/.gitignore @@ -0,0 +1,91 @@ +# 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 +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject +*.npy +*.pkl diff --git a/py_updater/setup.py/LICENSE b/py_updater/setup.py/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..6cd7b7924ef912ad8804e18ab2efd0c08b64d2e1 --- /dev/null +++ b/py_updater/setup.py/LICENSE @@ -0,0 +1,7 @@ +Copyright + +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. diff --git a/py_updater/setup.py/MANIFEST.in b/py_updater/setup.py/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..4fc9608f0bcdbe48ff566d849bb56501036c425f --- /dev/null +++ b/py_updater/setup.py/MANIFEST.in @@ -0,0 +1,3 @@ +include README.md LICENSE +recursive-include pdcopyist *.* +prune pdcopyist/**/__pycache__ \ No newline at end of file diff --git a/py_updater/setup.py/README.md b/py_updater/setup.py/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d53972bdc5a81f42c5e6aaf160ea6f3422094910 --- /dev/null +++ b/py_updater/setup.py/README.md @@ -0,0 +1,65 @@ +📦 setup.py (for humans) +======================= + +This repo exists to provide [an example setup.py] file, that can be used +to bootstrap your next Python project. It includes some advanced +patterns and best practices for `setup.py`, as well as some +commented–out nice–to–haves. + +For example, this `setup.py` provides a `$ python setup.py upload` +command, which creates a *universal wheel* (and *sdist*) and uploads +your package to [PyPi] using [Twine], without the need for an annoying +`setup.cfg` file. It also creates/uploads a new git tag, automatically. + +In short, `setup.py` files can be daunting to approach, when first +starting out — even Guido has been heard saying, "everyone cargo cults +thems". It's true — so, I want this repo to be the best place to +copy–paste from :) + +[Check out the example!][an example setup.py] + +Installation +----- + +```bash +cd your_project + +# Download the setup.py file: +# download with wget +wget https://raw.githubusercontent.com/navdeep-G/setup.py/master/setup.py -O setup.py + +# download with curl +curl -O https://raw.githubusercontent.com/navdeep-G/setup.py/master/setup.py +``` + +To Do +----- + +- Tests via `$ setup.py test` (if it's concise). + +Pull requests are encouraged! + +More Resources +-------------- + +- [What is setup.py?] on Stack Overflow +- [Official Python Packaging User Guide](https://packaging.python.org) +- [The Hitchhiker's Guide to Packaging] +- [Cookiecutter template for a Python package] + +License +------- + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any means. + + [an example setup.py]: https://github.com/navdeep-G/setup.py/blob/master/setup.py + [PyPi]: https://docs.python.org/3/distutils/packageindex.html + [Twine]: https://pypi.python.org/pypi/twine + [image]: https://farm1.staticflickr.com/628/33173824932_58add34581_k_d.jpg + [What is setup.py?]: https://stackoverflow.com/questions/1471994/what-is-setup-py + [The Hitchhiker's Guide to Packaging]: https://the-hitchhikers-guide-to-packaging.readthedocs.io/en/latest/creation.html + [Cookiecutter template for a Python package]: https://github.com/audreyr/cookiecutter-pypackage diff --git a/py_updater/setup.py/run.py b/py_updater/setup.py/run.py new file mode 100644 index 0000000000000000000000000000000000000000..70bc6a7af37d69fd5e397b3efb622596e4b0409d --- /dev/null +++ b/py_updater/setup.py/run.py @@ -0,0 +1,11 @@ + + +import shutil +import os +import pathlib + +os.chdir(pathlib.Path(__file__).parent) + +shutil.rmtree('dist', ignore_errors=True) +os.system('python setup.py sdist') +os.system('twine upload dist/*') diff --git a/py_updater/setup.py/setup.py b/py_updater/setup.py/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..56b0f3d0075944ee8dd4d8af89f5c5b07b115024 --- /dev/null +++ b/py_updater/setup.py/setup.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Note: To use the 'upload' functionality of this file, you must: +# $ pipenv install twine --dev + +import io +import os +import sys +from shutil import rmtree + +from setuptools import find_packages, setup, Command + +# Package meta-data. +NAME = 'pdcopyist_updater' +DESCRIPTION = 'A visual data manipulation tool that automatically generates python code' +URL = 'https://gitee.com/carson_add/pandas-ui' +EMAIL = '568166495@qq.com' +AUTHOR = 'Carson Liang' +REQUIRES_PYTHON = '>=3.6.0' +VERSION = '0.2.0' + +# What packages are required for this module to be executed? +REQUIRED = [ + 'pdcopyist' +] + +# What packages are optional? +EXTRAS = { + # 'pd read feather file': ['feather'], +} + +# The rest you shouldn't have to touch too much :) +# ------------------------------------------------ +# Except, perhaps the License and Trove Classifiers! +# If you do change the License, remember to change the Trove Classifier for that! + +here = os.path.abspath(os.path.dirname(__file__)) + +# Import the README and use it as the long-description. +# Note: this will only work if 'README.md' is present in your MANIFEST.in file! +try: + with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = '\n' + f.read() +except FileNotFoundError: + long_description = DESCRIPTION + +# Load the package's __version__.py module as a dictionary. +about = {} +if not VERSION: + project_slug = NAME.lower().replace("-", "_").replace(" ", "_") + with open(os.path.join(here, project_slug, '__version__.py')) as f: + exec(f.read(), about) +else: + about['__version__'] = VERSION + + +class UploadCommand(Command): + """Support setup.py upload.""" + + description = 'Build and publish the package.' + user_options = [] + + @staticmethod + def status(s): + """Prints things in bold.""" + print('\033[1m{0}\033[0m'.format(s)) + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + try: + self.status('Removing previous builds…') + rmtree(os.path.join(here, 'dist')) + except OSError: + pass + + self.status('Building Source and Wheel (universal) distribution…') + os.system( + '{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) + + self.status('Uploading the package to PyPI via Twine…') + os.system('twine upload dist/*') + + self.status('Pushing git tags…') + os.system('git tag v{0}'.format(about['__version__'])) + os.system('git push --tags') + + sys.exit() + + +# Where the magic happens: +setup( + name=NAME, + version=about['__version__'], + description=DESCRIPTION, + long_description=long_description, + long_description_content_type='text/markdown', + author=AUTHOR, + author_email=EMAIL, + python_requires=REQUIRES_PYTHON, + url=URL, + packages=[NAME], + + entry_points={ + 'console_scripts': [ + f'{NAME} = {NAME}.main:main' + ] + }, + + + # If your package is a single module, use this instead of 'packages': + # py_modules=['mypackage'], + + # entry_points={ + # 'console_scripts': ['mycli=mymodule:cli'], + # }, + + + + install_requires=REQUIRED, + extras_require=EXTRAS, + include_package_data=True, + license='MIT', + classifiers=[ + # Trove classifiers + # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy' + ], + # $ setup.py publish support. + cmdclass={ + 'upload': UploadCommand, + }, +) diff --git a/py_updater/workspace.code-workspace b/py_updater/workspace.code-workspace new file mode 100644 index 0000000000000000000000000000000000000000..876a1499c09dc083612f43c53c0ae71b9c30c5b1 --- /dev/null +++ b/py_updater/workspace.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file