diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..0d9360d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug, help wanted +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..cc98b69 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement, question +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..9ccc736 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +### Summary :memo: +_Write an overview about it._ + +### Details +_Describe more what you did on changes._ +1. (...) +2. (...) + +### Bugfixes :bug: (delete if dind't have any) +- + +### Checks +- [ ] Closed #798 +- [ ] Tested Changes +- [ ] Stakeholder Approval diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..120c689 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" \ No newline at end of file diff --git a/.github/init.sh b/.github/init.sh new file mode 100755 index 0000000..8a32ee3 --- /dev/null +++ b/.github/init.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +overwrite_template_dir=0 + +while getopts t:o flag +do + case "${flag}" in + t) template=${OPTARG};; + o) overwrite_template_dir=1;; + esac +done + +if [ -z "${template}" ]; then + echo "Available templates: flask" + read -p "Enter template name: " template +fi + +repo_urlname=$(basename -s .git `git config --get remote.origin.url`) +repo_name=$(basename -s .git `git config --get remote.origin.url` | tr '-' '_' | tr '[:upper:]' '[:lower:]') +repo_owner=$(git config --get remote.origin.url | awk -F ':' '{print $2}' | awk -F '/' '{print $1}') +echo "Repo name: ${repo_name}" +echo "Repo owner: ${repo_owner}" +echo "Repo urlname: ${repo_urlname}" + +if [ -f ".github/workflows/rename_project.yml" ]; then + .github/rename_project.sh -a "${repo_owner}" -n "${repo_name}" -u "${repo_urlname}" -d "Awesome ${repo_name} created by ${repo_owner}" +fi + +function download_template { + rm -rf "${template_dir}" + mkdir -p .github/templates + git clone "${template_url}" "${template_dir}" +} + +echo "Using template:${template}" +template_url="https://github.com/rochacbruno/${template}-project-template" +template_dir=".github/templates/${template}" +if [ -d "${template_dir}" ]; then + # Template directory already exists + if [ "${overwrite_template_dir}" -eq 1 ]; then + # user passed -o flag, delete and re-download + echo "Overwriting ${template_dir}" + download_template + else + # Ask user if they want to overwrite + echo "Directory ${template_dir} already exists." + read -p "Do you want to overwrite it? [y/N] " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "Overwriting ${template_dir}" + download_template + else + # User decided not to overwrite + echo "Using existing ${template_dir}" + fi + fi +else + # Template directory does not exist, download it + echo "Downloading ${template_url}" + download_template +fi + +echo "Applying ${template} template to this project"} +./.github/templates/${template}/apply.sh -a "${repo_owner}" -n "${repo_name}" -u "${repo_urlname}" -d "Awesome ${repo_name} created by ${repo_owner}" + +# echo "Removing temporary template files" +# rm -rf .github/templates/${template} + +echo "Done! review, commit and push the changes" diff --git a/.github/rename_project.sh b/.github/rename_project.sh new file mode 100755 index 0000000..4459ea9 --- /dev/null +++ b/.github/rename_project.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +while getopts a:n:u:d: flag +do + case "${flag}" in + a) author=${OPTARG};; + n) name=${OPTARG};; + u) urlname=${OPTARG};; + d) description=${OPTARG};; + esac +done + +echo "Author: $author"; +echo "Project Name: $name"; +echo "Project URL name: $urlname"; +echo "Description: $description"; + +echo "Renaming project..." + +original_author="UKPLab" +original_name="ukp_project_template" +original_urlname="ukp-project-template" +original_description="The official template for new Python projects at UKP Lab" +# Iterate over all files in the repository +git ls-files | while read -r filename; do + # Exclude .github/workflows/rename_project.yml from renaming + if [[ "$filename" != ".github/workflows/rename_project.yml" ]]; then + sed -i "s/$original_author/$author/g" "$filename" + sed -i "s/$original_name/$name/g" "$filename" + sed -i "s/$original_urlname/$urlname/g" "$filename" + sed -i "s/$original_description/$description/g" "$filename" + echo "Renamed $filename" + else + echo "Skipping $filename" + fi +done + +mv "$original_name" "$name" + +# This command runs only once on GHA! +rm -rf .github/template.yml diff --git a/.github/template.yml b/.github/template.yml new file mode 100644 index 0000000..94e4e54 --- /dev/null +++ b/.github/template.yml @@ -0,0 +1 @@ +author: UKPLab diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..45c94f6 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,31 @@ +name: Build Docs + +on: + push: + branches: + - main # Change this to your main branch name + pull_request: + branches: + - main # Change this to your main branch name + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.9 # Change this to your Python version + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + + - name: Build Docs + run: | + python -m mkdocs build --verbose diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..0d39a67 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,70 @@ +# This is a basic workflow to help you get started with Actions +name: CI + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [ main ] + pull_request: + branches: [ main ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + + check-files: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Check files + run: | + # Define the list of filenames you want to check + FILES_TO_CHECK=("LICENSE" "README.md" "requirements.txt" "requirements-dev.txt" "NOTICE.txt" "setup.py") + + # Initialize a variable to track missing files + MISSING_FILES=() + + # Check if each file exists in the root directory + for FILE in "${FILES_TO_CHECK[@]}"; do + if [ ! -f "$FILE" ]; then + MISSING_FILES+=("$FILE") + fi + done + + # Output the missing files + if [ ${#MISSING_FILES[@]} -eq 0 ]; then + echo "All files exist." + else + echo "The following files are missing:" + for MISSING_FILE in "${MISSING_FILES[@]}"; do + echo "- $MISSING_FILE" + done + echo "::error::One or more files are missing." + exit 1 + fi + + linter: + runs-on: ubuntu-latest + needs: check-files + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + pip install -r requirements-dev.txt + + - name: Analysing the code with pylint + run: | + pylint --disable=trailing-whitespace,missing-class-docstring,missing-final-newline,trailing-newlines \ + --fail-under=9.0 \ + $(git ls-files '*.py') || echo "::warning::Pylint check failed, but the workflow will continue." diff --git a/.github/workflows/rename_project.yml b/.github/workflows/rename_project.yml new file mode 100644 index 0000000..4cef27e --- /dev/null +++ b/.github/workflows/rename_project.yml @@ -0,0 +1,42 @@ +name: Rename the project from template + +on: [push] + +permissions: write-all + +jobs: + rename-project: + if: ${{ !contains (github.repository, '/ukp-project-template') }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # by default, it uses a depth of 1 + # this fetches all history so that we can read each commit + fetch-depth: 0 + ref: ${{ github.head_ref }} + + - run: echo "REPOSITORY_NAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}' | tr '-' '_' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV + shell: bash + + - run: echo "REPOSITORY_URLNAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_ENV + shell: bash + + - run: echo "REPOSITORY_OWNER=$(echo '${{ github.repository }}' | awk -F '/' '{print $1}')" >> $GITHUB_ENV + shell: bash + + - name: Is this still a template + id: is_template + run: echo "::set-output name=is_template::$(ls .github/template.yml &> /dev/null && echo true || echo false)" + + - name: Rename the project + if: steps.is_template.outputs.is_template == 'true' + run: | + echo "Renaming the project with -a(author) ${{ env.REPOSITORY_OWNER }} -n(name) ${{ env.REPOSITORY_NAME }} -u(urlname) ${{ env.REPOSITORY_URLNAME }}" + .github/rename_project.sh -a ${{ env.REPOSITORY_OWNER }} -n ${{ env.REPOSITORY_NAME }} -u ${{ env.REPOSITORY_URLNAME }} -d "Awesome ${{ env.REPOSITORY_NAME }} created by ${{ env.REPOSITORY_OWNER }}" + + - uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "βœ… Ready to clone and code." + # commit_options: '--amend --no-edit' + push_options: --force diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..6a171a5 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,49 @@ +# This is a basic workflow to help you get started with Actions +name: Run tests + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [ main ] + pull_request: + branches: [ main ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + tests: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + pip install . + pip install -r requirements-dev.txt + + # Hacky way to get package name from setup.py + - name: Get package name + id: get_package_name + run: | + setup_file="setup.py" + pattern="name=" + project_name=$(grep -oP "(?<=${pattern}\")[^\"]+" $setup_file) + echo "::set-output name=package_name::$project_name" + + - name: Run tests + run: | + pytest -v --cov-fail-under=60 --cov=${{ steps.get_package_name.outputs.package_name }} -l --tb=short --maxfail=1 tests/ + coverage xml + coverage html \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e550cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,139 @@ +# 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/ + +# templates +.github/templates/* + +# History +.history + +# Project files +sketch* +ukp_project_template/sketch* \ No newline at end of file diff --git a/ABOUT_THIS_TEMPLATE.md b/ABOUT_THIS_TEMPLATE.md new file mode 100644 index 0000000..82291f1 --- /dev/null +++ b/ABOUT_THIS_TEMPLATE.md @@ -0,0 +1,125 @@ +# About this template + +Hi, I've adapted this template from the excellent [python-project-template](https://github.com/rochacbruno/python-project-template/) by [rochacbruno](https://github.com/rochacbruno). It was created having in mind UKP Lab people and what the most common use-cases would be. Following its structure you'll get into developing your next paper in no time! + +It includes: + +- πŸ“¦ A basic [setup.py](setup.py) file to provide installation, packaging and distribution for your project. + Template uses setuptools because it's the de-facto standard for Python packages +- πŸ“ƒ Documentation structure using [mkdocs](http://www.mkdocs.org) +- πŸ§ͺ Testing structure using [pytest](https://docs.pytest.org/en/latest/) +- βœ… Code linting using [pylint](https://pypi.org/project/pylint/) +- 🎯 Entry points to execute your program using `python -m ` with basic CLI argument parsing. +- πŸ”„ Continuous integration using [Github Actions](https://github.com/UKPLab/ukp-project-template/actions) with jobs to check, lint and test your project. + +Are there any changes you'd like to request? Feel free to fork and open a pull request! + +## Structure + +Lets take a look at the structure of this template: + +```text +β”‚ .gitignore # A list of files to ignore when pushing to GH +β”‚ ABOUT_THIS_TEMPLATE.md # The file you're reading right now +β”‚ LICENSE # The license for the project +β”‚ mkdocs.yml # Configuration for documentation site +β”‚ NOTICE.txt # Legal notice for the repository +β”‚ README.md # The main readme for the project +β”‚ requirements-dev.txt # List of requirements for testing and devlopment +β”‚ requirements.txt # An empty file to hold the requirements for the project +β”‚ setup.py # The setup.py file for installing and packaging the project +β”‚ +β”œβ”€β”€β”€.github # Github metadata for repository +β”‚ β”‚ dependabot.yml # Dependabot workflow for updating requirements +β”‚ β”‚ init.sh # Initializes the repository +β”‚ β”‚ PULL_REQUEST_TEMPLATE.md # Used automatically by GH for pull requests +β”‚ β”‚ rename_project.sh # Called once at repository creation +β”‚ β”‚ +β”‚ β”œβ”€β”€β”€ISSUE_TEMPLATE # Templates for creating issues on GH +β”‚ β”‚ +β”‚ └───workflows # GH Actions folder +β”‚ docs.yml # Builds documentation automatically +β”‚ main.yml # Runs install and file checks +β”‚ rename_project.yml # Renames repository at creation +β”‚ tests.yml # Run all tests in 'tests' folder +β”‚ +β”œβ”€β”€β”€docs # Auto-generated documentation +β”‚ index.md # Landing page of docs +β”‚ +β”œβ”€β”€β”€ukp_project_template # The main python package for the project +β”‚ base.py # The base module for the project +β”‚ cli.py # Defines CLI instructions +β”‚ __init__.py # This tells Python that this is a package +β”‚ __main__.py # The entry point for the project +β”‚ +└───tests # Unit tests for the project (add more tests files here) + conftest.py # Configuration, hooks and fixtures for pytest + test_base.py # The base test case for the project + __init__.py # This tells Python that this is a test package +``` + +## FAQs + + +### Where should I add new stuff ? + +You should create new files and subpackages inside ukp_project_template and implement your functionalities there. Remember to add what you write to `__init__.py` so that the imports work smoothly. Take a look at `base.py` and `__init__.py` to understand how it works. + +### Why is `requirements.txt` empty ? + +This template is a low dependency project, so it doesn't have any extra dependencies. +You can freely add new dependencies. + +You should put here everything needed to replicate your work. +Testing, linting, and other requirements used only in development should go in `requirements-dev.txt`. + +### Why is there a `requirements-dev.txt` file ? + +This file lists all the requirements for testing and development. Use it to separate things you used during development from the essential stuff needed to replicate your work. + +### What is the `.github` folder? + +It contains [GitHub Actions](https://docs.github.com/en/actions) that are executed automatically when pushing your code. You can see results for your repository [here](https://github.com/UKPLab/ukp-project-template/actions). + +### What does the linter workflow do? + +It checks whether your code is clean enough from duplication, inconsistencies, violations to the naming convention etc. +It's not supposed to fail, but you should still look into it to get an idea of which parts of your code may need adjustments. + +### Why do automated actions fail ? + +This means there is something wrong in the files/tests/requirements. +Click on the failing run to read more details. + +### Why include `tests` and `docs` as part of the release? + +This template ships with everything you may need. You can remove what you don't like in this way: + - If you don't need automatic documentation generation, you can delete folder `docs`, file `.github\workflows\docs.yml` and `mkdocs.yml` + - If you don't want automatic testing, you can delete folder `tests` and file `.github\workflows\tests.yml` + +### How can I use pytest & pylint to check my code? + +Command `pytest` called from the project folder will run all tests inside the `tests` folder. +Similarly, `pylint` will run linting checks on your code and give you a status report. +It checks things such as logic, formatting, correct imports, duplication etc. + +### Why conftest includes a go_to_tmpdir fixture? + +When your project deals with file system operations, it is a good idea to use +a fixture to create a temporary directory and then remove it after the test. + +Before executing each test pytest will create a temporary directory and will +change the working directory to that path and run the test. + +So the test can create temporary artifacts isolated from other tests. + +After the execution Pytest will remove the temporary directory. + +### Why this template is not using [pre-commit](https://pre-commit.com/) ? + +pre-commit is an excellent tool to automate checks and formatting on your code. + +However I figured out that pre-commit adds extra dependency and it an entry barrier +for new contributors. + +Once the project is bigger and complex, having pre-commit as a dependency can be a good idea. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 0000000..94a0ec8 --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,9 @@ +------------------------------------------------------------------------------- +Copyright 2024 +Ubiquitous Knowledge Processing (UKP) Lab +Technische UniversitΓ€t Darmstadt + +------------------------------------------------------------------------------- +Third party legal information + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..441b6c2 --- /dev/null +++ b/README.md @@ -0,0 +1,115 @@ +

+ +

+ +# ukp_project_template +[![Arxiv](https://img.shields.io/badge/Arxiv-YYMM.NNNNN-red?style=flat-square&logo=arxiv&logoColor=white)](https://put-here-your-paper.com) +[![License](https://img.shields.io/github/license/UKPLab/ukp-project-template)](https://opensource.org/licenses/Apache-2.0) +[![Python Versions](https://img.shields.io/badge/Python-3.9-blue.svg?style=flat&logo=python&logoColor=white)](https://www.python.org/) +[![CI](https://github.com/UKPLab/ukp-project-template/actions/workflows/main.yml/badge.svg)](https://github.com/UKPLab/ukp-project-template/actions/workflows/main.yml) + +This is the official template for new Python projects at UKP Lab. It was adapted for the needs of UKP Lab from the excellent [python-project-template](https://github.com/rochacbruno/python-project-template/) by [rochacbruno](https://github.com/rochacbruno). + +It should help you start your project and give you continuous status updates on the development through [GitHub Actions](https://docs.github.com/en/actions). + +> **Abstract:** The study of natural language processing (NLP) has gained increasing importance in recent years, with applications ranging from machine translation to sentiment analysis. Properly managing Python projects in this domain is of paramount importance to ensure reproducibility and facilitate collaboration. The template provides a structured starting point for projects and offers continuous status updates on development through GitHub Actions. Key features include a basic setup.py file for installation, packaging, and distribution, documentation structure using mkdocs, testing structure using pytest, code linting with pylint, and entry points for executing the program with basic CLI argument parsing. Additionally, the template incorporates continuous integration using GitHub Actions with jobs to check, lint, and test the project, ensuring robustness and reliability throughout the development process. + +Contact person: [Federico Tiblias](mailto:federico.tiblias@tu-darmstadt.de) + +[UKP Lab](https://www.ukp.tu-darmstadt.de/) | [TU Darmstadt](https://www.tu-darmstadt.de/ +) + +Don't hesitate to send us an e-mail or report an issue, if something is broken (and it shouldn't be) or if you have further questions. + + +## Getting Started + +> **DO NOT CLONE OR FORK** + +If you want to set up this template: + +1. Request a repository on UKP Lab's GitHub by following the standard procedure on the wiki. It will install the template directly. Alternatively, set it up in your personal GitHub account by clicking **[Use this template](https://github.com/rochacbruno/python-project-template/generate)**. +2. Wait until the first run of CI finishes. Github Actions will commit to your new repo with a "βœ… Ready to clone and code" message. +3. Delete optional files: + - If you don't need automatic documentation generation, you can delete folder `docs`, file `.github\workflows\docs.yml` and `mkdocs.yml` + - If you don't want automatic testing, you can delete folder `tests` and file `.github\workflows\tests.yml` +4. Prepare a virtual environment: +```bash +python -m venv .venv +source .venv/bin/activate +pip install . +pip install -r requirements-dev.txt # Only needed for development +``` +5. Adapt anything else (for example this file) to your project. + +6. Read the file [ABOUT_THIS_TEMPLATE.md](ABOUT_THIS_TEMPLATE.md) for more information about development. + +## Usage + +### Using the classes + +To import classes/methods of `ukp_project_template` from inside the package itself you can use relative imports: + +```py +from .base import BaseClass # Notice how I omit the package name + +BaseClass().something() +``` + +To import classes/methods from outside the package (e.g. when you want to use the package in some other project) you can instead refer to the package name: + +```py +from ukp_project_template import BaseClass # Notice how I omit the file name +from ukp_project_template.subpackage import SubPackageClass # Here it's necessary because it's a subpackage + +BaseClass().something() +SubPackageClass().something() +``` + +### Using scripts + +This is how you can use `ukp_project_template` from command line: + +```bash +$ python -m ukp_project_template +``` + +### Expected results + +After running the experiments, you should expect the following results: + +(Feel free to describe your expected results here...) + +### Parameter description + +* `x, --xxxx`: This parameter does something nice + +* ... + +* `z, --zzzz`: This parameter does something even nicer + +## Development + +Read the FAQs in [ABOUT_THIS_TEMPLATE.md](ABOUT_THIS_TEMPLATE.md) to learn more about how this template works and where you should put your classes & methods. Make sure you've correctly installed `requirements-dev.txt` dependencies + +## Cite + +Please use the following citation: + +``` +@InProceedings{smith:20xx:CONFERENCE_TITLE, + author = {Smith, John}, + title = {My Paper Title}, + booktitle = {Proceedings of the 20XX Conference on XXXX}, + month = mmm, + year = {20xx}, + address = {Gotham City, USA}, + publisher = {Association for XXX}, + pages = {XXXX--XXXX}, + url = {http://xxxx.xxx} +} +``` + +## Disclaimer + +> This repository contains experimental software and is published for the sole purpose of giving additional background details on the respective publication. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..fe27dfe --- /dev/null +++ b/docs/index.md @@ -0,0 +1,21 @@ +# Welcome to MkDocs + +For full documentation visit [mkdocs.org](https://www.mkdocs.org). + +## Commands + +* `mkdocs new [dir-name]` - Create a new project. +* `mkdocs serve` - Start the live-reloading docs server. +* `mkdocs build` - Build the documentation site. +* `mkdocs -h` - Print help message and exit. + +## Project layout + + mkdocs.yml # The configuration file. + docs/ + index.md # The documentation homepage. + ... # Other markdown pages, images and other files. + +## Docs + +::: ukp_project_template \ No newline at end of file diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..89f79d0 Binary files /dev/null and b/logo.png differ diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..83f9db2 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,15 @@ +site_name: ukp_project_template +nav: + - Home: index.md + +theme: + name: material + +plugins: + - search + - mkdocstrings: + project_name: ukp_project_template + handlers: + python: + options: + docstring_style: numpy \ No newline at end of file diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..829cafe --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,14 @@ +# This requirements are for development and testing only, not for production. +# You shouldn't need to edit this file, unless you know what you are doing. +pytest +coverage +pylint +black +isort +pytest-cov +mypy +gitchangelog +mkdocs +mkdocs-material +mkdocstrings +mkdocstrings-python diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2c0a27e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +# This template is low-dependency. +# By default there is no requirements added here. +# Add the requirements you need to this file. diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..dc33116 --- /dev/null +++ b/setup.py @@ -0,0 +1,44 @@ +"""Python setup.py for ukp_project_template package""" +import io +import os +from setuptools import find_packages, setup + + +def read(*paths, **kwargs): + """Read the contents of a text file safely. + >>> read("ukp_project_template", "VERSION") + '0.1.0' + >>> read("README.md") + ... + """ + + content = "" + with io.open( + os.path.join(os.path.dirname(__file__), *paths), + encoding=kwargs.get("encoding", "utf8"), + ) as open_file: + content = open_file.read().strip() + return content + + +def read_requirements(path): + return [ + line.strip() + for line in read(path).split("\n") + if not line.startswith(('"', "#", "-", "git+")) + ] + + +setup( + name="ukp_project_template", + url="https://github.com/UKPLab/ukp-project-template/", + long_description=read("README.md"), + long_description_content_type="text/markdown", + author="author_name", + packages=find_packages(exclude=["tests", ".github"]), + install_requires=read_requirements("requirements.txt"), + entry_points={ + "console_scripts": ["ukp_project_template = ukp_project_template.__main__:main"] + }, + extras_require={"test": read_requirements("requirements-dev.txt")}, +) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..2dc2a8f --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,17 @@ +# This file defines fixtures that are used by all tests in the tests/ directory. +# See https://docs.pytest.org/en/latest/fixture.html for more information about fixtures. + +import sys +import pytest + + +# each test runs on cwd to its temp dir +@pytest.fixture(autouse=True) +def go_to_tmpdir(request): + # Get the fixture dynamically by its name. + tmpdir = request.getfixturevalue("tmpdir") + # ensure local test created packages can be imported + sys.path.insert(0, str(tmpdir)) + # Chdir only for the duration of the test. + with tmpdir.as_cwd(): + yield diff --git a/tests/test_base.py b/tests/test_base.py new file mode 100644 index 0000000..6eac760 --- /dev/null +++ b/tests/test_base.py @@ -0,0 +1,22 @@ +# Tests are defined here +from ukp_project_template import BaseClass +from ukp_project_template.subpackage import SubPackageClass + +def test_template(): + assert True + +def test_base_class(): + bc1 = BaseClass(name="test1") + bc2 = BaseClass(name="test2") + + assert str(bc1) == "test1" + assert repr(bc1) == "test1" + assert bc1 != bc2 + assert bc1.something() == "something" + +def test_subpackage(): + spc = SubPackageClass(name="test") + + assert str(spc) == "SubPackage - test" + assert repr(spc) == "SubPackage - test" + assert spc.something() == "SubPackage - something" \ No newline at end of file diff --git a/ukp_project_template/__init__.py b/ukp_project_template/__init__.py new file mode 100644 index 0000000..4003b3e --- /dev/null +++ b/ukp_project_template/__init__.py @@ -0,0 +1,8 @@ +from .base import BaseClass + + + +__all__ = [ + "subpackage", + "BaseClass" + ] \ No newline at end of file diff --git a/ukp_project_template/__main__.py b/ukp_project_template/__main__.py new file mode 100644 index 0000000..c6bc87c --- /dev/null +++ b/ukp_project_template/__main__.py @@ -0,0 +1,6 @@ +"""Entry point for ukp_project_template.""" + +from .cli import main # pragma: no cover + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/ukp_project_template/base.py b/ukp_project_template/base.py new file mode 100644 index 0000000..7ecc6ac --- /dev/null +++ b/ukp_project_template/base.py @@ -0,0 +1,62 @@ +# Example class +class BaseClass: + """ + Base class representing an entity. + + Attributes + ---------- + name : str + The name of the entity. + + Methods + ------- + __init__(): + Initializes a new instance of the BaseClass. + __str__(): + Returns a string representation of the entity. + __repr__(): + Returns a string representation of the entity for debugging. + __eq__(other): + Checks if two entities are equal based on their names. + + """ + + def __init__(self, name: str): + """ + Initializes a new instance of the BaseClass. + """ + self.name = name + + def __str__(self): + """ + Returns a string representation of the entity. + """ + return self.name + + def __repr__(self): + """ + Returns a string representation of the entity for debugging. + """ + return self.name + + def __eq__(self, other): + """ + Checks if two entities are equal based on their names. + + Parameters + ---------- + other : BaseClass + Another instance of BaseClass. + + Returns + ------- + bool + True if the entities are equal, False otherwise. + """ + return self.name == other.name + + def something(self): + """ + Does something. + """ + return "something" diff --git a/ukp_project_template/cli.py b/ukp_project_template/cli.py new file mode 100644 index 0000000..325b7c9 --- /dev/null +++ b/ukp_project_template/cli.py @@ -0,0 +1,33 @@ +"""CLI interface for ukp_project_template project. + +Be creative! do whatever you want! + +- Install click or typer and create a CLI app +- Use builtin argparse +- Start a web application +- Import things from your .base module +""" +from .base import BaseClass +from .subpackage import SubPackageClass + +def main(): # pragma: no cover + """ + The main function executes on commands: + `python -m ukp_project_template` and `$ ukp_project_template `. + + This is your program's entry point. + + You can change this function to do whatever you want. + Examples: + * Run a test suite + * Run a server + * Do some other stuff + * Run a command line application (Click, Typer, ArgParse) + * List all available tasks + * Run an application (Flask, FastAPI, Django, etc.) + """ + bc = BaseClass("test") + print(f"This will do something: {bc.something()}") + + spc = SubPackageClass("test") + print(f"This will do something else: {spc.something()}") diff --git a/ukp_project_template/subpackage/__init__.py b/ukp_project_template/subpackage/__init__.py new file mode 100644 index 0000000..bf2baf1 --- /dev/null +++ b/ukp_project_template/subpackage/__init__.py @@ -0,0 +1,5 @@ +from .subpackage import SubPackageClass + +__all__ = [ + "SubPackageClass" +] \ No newline at end of file diff --git a/ukp_project_template/subpackage/subpackage.py b/ukp_project_template/subpackage/subpackage.py new file mode 100644 index 0000000..c676ed5 --- /dev/null +++ b/ukp_project_template/subpackage/subpackage.py @@ -0,0 +1,15 @@ +class SubPackageClass: + def __init__(self, name): + self.name = name + + def __str__(self): + return f"SubPackage - {self.name}" + + def __repr__(self): + return f"SubPackage - {self.name}" + + def __eq__(self, other): + return self.name == other.name + + def something(self): + return "SubPackage - something" \ No newline at end of file