From bc952baf68fb296701a408178f529995be83d262 Mon Sep 17 00:00:00 2001 From: Nathan Hui Date: Fri, 10 Feb 2023 14:16:13 -0800 Subject: [PATCH] Initial commit --- .github/workflows/pylint.yml | 23 ++++ .gitignore | 129 +++++++++++++++++++++++ .vscode/launch.json | 23 ++++ .vscode/settings.json | 7 ++ README.md | 30 ++++++ example.ipynb | 164 +++++++++++++++++++++++++++++ example_package/__init__.py | 0 example_package/example_module.py | 38 +++++++ python-repo-example.code-workspace | 21 ++++ setup.py | 17 +++ tests/test_module.py | 15 +++ 11 files changed, 467 insertions(+) create mode 100644 .github/workflows/pylint.yml create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 100644 example.ipynb create mode 100644 example_package/__init__.py create mode 100644 example_package/example_module.py create mode 100644 python-repo-example.code-workspace create mode 100644 setup.py create mode 100644 tests/test_module.py diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml new file mode 100644 index 0000000..0ad87c3 --- /dev/null +++ b/.github/workflows/pylint.yml @@ -0,0 +1,23 @@ +name: Pylint + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10"] + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pylint + - name: Analysing the code with pylint + run: | + pylint $(git ls-files '*.py') \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6e4761 --- /dev/null +++ b/.gitignore @@ -0,0 +1,129 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# 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/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..1752517 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,23 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Run Module", + "type": "python", + "request": "launch", + "module": "examplePackage.exampleModule", + "justMyCode": true + }, + { + "name": "Python: Run File", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/examplePackage/exampleModule.py", + "console": "integratedTerminal", + "justMyCode": true + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9b38853 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..79b4664 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# python-repo-example +Example Python Package Repository. This repository serves as an example of how to set up a Python repository for UCSD Engineers for Exploration. + +## .vscode +This folder should contain at least a `launch.json` file that provides entry points into the package. This could be entry points to example programs, typical debug entry points, etc. Ideally, this will also contain a `settings.json` with folder specific VS Code settings. + +## Python Packages +Almost all code should be organized into packages. This facilitates easy code reuse. See https://packaging.python.org/en/latest/ for more information on how to use packages in Python. + +## tests +Tests should ideally be kept in an isolated folder. This example uses `pytest`, see https://docs.pytest.org/en/7.0.x/ for information on how to use `pytest`. + +## .gitignore +This is an important file to put into your `git` repositories. This helps prevent `git` from including unnecessary files into the version control system, such as generated files, environment files, or log files. + +## Jupyter Notebooks +Jupyter Notebooks are a great way to add interactive reports or documentation. There is an example here. + +## *.code-workspace +This is created by going to `File`->`Save Workspace As` in VS Code. This allows us to easily open the same development environment across computers and operating systems. Use this as the root of your development environment. + +You'll also notice here that there are some recommended extensions. This allows everyone on your team to have a consistent toolchain for how to interact with your code. See https://code.visualstudio.com/docs/editor/extension-marketplace#_workspace-recommended-extensions for instructions for how to configure these. + +## README.md +This is a critical file to include. This should be an introduction to your repository. It should be a birds-eye view of what your repo is and how to use it, with links to the appropriate lower-level documentation. + +## setup.py +This is the original way to package Python projects, which we probably still prefer. However, in general, if you can, you should probably start using the newer packaging tools (`pyproject.toml`) + +See https://packaging.python.org/en/latest/tutorials/packaging-projects/ and https://docs.python.org/3/distutils/setupscript.html for more information about each tool. \ No newline at end of file diff --git a/example.ipynb b/example.ipynb new file mode 100644 index 0000000..2596cb3 --- /dev/null +++ b/example.ipynb @@ -0,0 +1,164 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from examplePackage import example_module" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following function simply prints out a message to the console or Jupyter Notebook output" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is a function that does something\n" + ] + } + ], + "source": [ + "example_module.example_function()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following function returns a value that we can then display" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'This function returned a string'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "example_module.example_returning_function()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following function takes in some arguments and returns something that we can then display. We first define those inputs in a separate cell, then execute in a different cell" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "integer_argument = 1\n", + "list_of_strings = [\n", + " \"stringA\",\n", + " \"stringB\",\n", + " \"stringC\"\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'stringA1stringB1stringC'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "complex_return = example_module.example_complex_function(arg_a=integer_argument, arg_b=list_of_strings)\n", + "complex_return" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice in the previous cell we stored the output into a variable so we can reference it later" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['stringA', 'stringB', 'stringC']\n" + ] + } + ], + "source": [ + "print(complex_return.split(f'{integer_argument}'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.8 ('.venv': venv)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.8" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "421775ed80caccaec9c1b756b8df10049297c25e50d4d1d4e76c6661c534363c" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/example_package/__init__.py b/example_package/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/example_package/example_module.py b/example_package/example_module.py new file mode 100644 index 0000000..6319a26 --- /dev/null +++ b/example_package/example_module.py @@ -0,0 +1,38 @@ +"""Example module +""" +from typing import List + +def example_function() -> None: + """Example function that prints out a message + """ + print("This is a function that does something") + +def example_returning_function() -> str: + """Example function that returns a value + + Returns: + str: Example return value + """ + return "This function returned a string" + +def example_complex_function(arg_a: int, arg_b: List[str]) -> str: + """Example function that does something complex with a function + + Args: + a (int): Number to insert between strings + b (List[str]): Strings to combine + + Returns: + str: String in b concatenated using the string representation of a + """ + return f'{arg_a}'.join(arg_b) + +def example_entry_point() -> None: + """Example entry point that exersizes all of the module's functions + """ + example_function() + print(example_returning_function()) + print(f"This is a complex function: {example_complex_function(3, ['asdf', 'foo', 'bar'])}") + +if __name__ == "__main__": + example_entry_point() diff --git a/python-repo-example.code-workspace b/python-repo-example.code-workspace new file mode 100644 index 0000000..3ac3097 --- /dev/null +++ b/python-repo-example.code-workspace @@ -0,0 +1,21 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "python.linting.pylintEnabled": true, + "editor.rulers": [ + 100 + ] + }, + "extensions": { + "recommendations": [ + "ms-python.vscode-pylance", + "ms-python.python", + "ms-toolsai.jupyter", + "njpwerner.autodocstring" + ] + } +} \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7bc0801 --- /dev/null +++ b/setup.py @@ -0,0 +1,17 @@ +"""Example setup file +""" +from setuptools import setup, find_packages + +setup( + name='example_package', + version='0.0.0.1', + author='UCSD Engineers for Exploration', + author_email='e4e@eng.ucsd.edu', + entry_points={ + 'console_scripts': [ + 'ExamplePythonConsoleScript = example_package.example_module:exampleEntryPoint' + ] + }, + packages=find_packages(), + install_requires=[] +) diff --git a/tests/test_module.py b/tests/test_module.py new file mode 100644 index 0000000..d7d936f --- /dev/null +++ b/tests/test_module.py @@ -0,0 +1,15 @@ +"""Example test module +""" +from example_package import example_module + +def test_example_function(): + """Tests that the example function completes successfully + """ + example_module.example_function() + assert True + +def test_example_return(): + """Tests that the function returns something + """ + retval = example_module.example_returning_function() + assert retval is not None