diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..179dfba
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,20 @@
+# Editor Configuration (http://editorconfig.org)
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 4
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+max_line_length = 88
+
+[*.{json,yml,yaml}]
+indent_size = 2
+
+[*.{md,rst}]
+trim_trailing_whitespace = false
+
+[Makefile]
+indent_style = tab
diff --git a/.github/ISSUE_TEMPLATE/01-bug-report.yml b/.github/ISSUE_TEMPLATE/01-bug-report.yml
new file mode 100644
index 0000000..bf7ff69
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/01-bug-report.yml
@@ -0,0 +1,68 @@
+name: 🐞 Bug report
+description: Report a problem to help improve this project
+title: "[BUG] "
+labels: [bug, triage]
+body:
+ - type: checkboxes
+ attributes:
+ label: Is there an existing issue for this?
+ description: Please search to see if an issue already exists for the bug you encountered.
+ options:
+ - label: I have searched the existing issues
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Problem description
+ description: |
+ A concise description of what you're experiencing.
+
+ Please explain:
+
+ * **what** you tried to achieve,
+ * **how** you went about it (referring to the code sample), and
+ * **why** the current behaviour is a problem and what output you expected instead.
+ validations:
+ required: false
+
+ - type: textarea
+ attributes:
+ label: Code sample
+ description: >
+ Create a [minimal, complete, verifiable example](https://stackoverflow.com/help/mcve).
+ Please, paste your code between the ``` tickmarks below or link to a [gist](https://gist.github.com/).
+ value: |
+ Code run:
+
+ ```python
+ ```
+
+ Traceback:
+
+ ```text
+ ```
+ validations:
+ required: false
+
+ - type: textarea
+ attributes:
+ label: Environment
+ description: >
+ Please paste the output of running `depinfo --markdown pyospackage_montuygl`
+ in your environment between the `details` tags below.
+ value: |
+
+
+
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Anything else?
+ description: |
+ Links? References? Anything that will give us more context about the issue you are encountering!
+
+ Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..0d86fab
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: true
+contact_links:
+ - name: Community Support
+ url: https://github.com/montuygl/pyospackage_montuygl/discussions
+ about: Please ask and answer questions here.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..6ca7742
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,4 @@
+- [ ] fix #(issue number)
+- [ ] description of feature/fix
+- [ ] tests added/passed
+- [ ] add an entry to the [changelog](../CHANGELOG.md)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..9b45e8d
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,74 @@
+name: Publish to PyPI
+
+on:
+ release:
+ types: [published]
+
+jobs:
+ prerequisites:
+ uses: ./.github/workflows/test.yml
+ # Setup build separate from publish for added security
+ # See https://github.com/pypa/gh-action-pypi-publish/issues/217#issuecomment-1965727093
+ build:
+ needs: [prerequisites]
+ runs-on: ubuntu-latest
+ # Environment is encouraged for increased security
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ # This fetch element is only important if you are use SCM based
+ # versioning (that looks at git tags to gather the version).
+ # setuptools-scm needs tags to form a valid version number
+ fetch-tags: true
+
+ - name: Setup Python
+ uses: actions/setup-python@v5
+ with:
+ # You can modify what version of Python you want to use for your release
+ python-version: "3.11"
+
+ # Security recommends we should pin deps. Should we pin the workflow version?
+ - name: Install hatch
+ uses: pypa/hatch@a3c83ab3d481fbc2dc91dd0088628817488dd1d5
+
+ - name: Build package using Hatch
+ run: |
+ hatch build
+ echo ""
+ echo "Generated files:"
+ ls -lh dist/
+
+ # Store an artifact of the build to use in the publish step below
+ - name: Store the distribution packages
+ uses: actions/upload-artifact@v4
+ with:
+ name: python-package-distributions
+ path: dist/
+ if-no-files-found: error
+ publish:
+ name: >-
+ Publish Python 🐍 distribution 📦 to PyPI
+ # Modify the repo name below to be your project's repo name.
+ if: github.repository_owner == "{{ username }}"
+ needs:
+ - build
+ runs-on: ubuntu-latest
+ # Environment required here for trusted publisher
+ environment:
+ name: pypi
+ # Modify the url to be the name of your package
+ url: https://pypi.org/p/${{ package_name }}
+ permissions:
+ id-token: write # this permission is mandatory for PyPI publishing
+ steps:
+ - name: Download dists
+ uses: actions/download-artifact@v4
+ with:
+ name: python-package-distributions
+ path: dist/
+ merge-multiple: true
+ - name: Publish package to PyPI
+ # Only publish to real PyPI on release
+ if: github.event_name == 'release' && github.event.action == 'published'
+ uses: pypa/gh-action-pypi-publish@release/v1
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..0e2f422
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,36 @@
+name: Test Suite
+
+on:
+ workflow_dispatch: {}
+ workflow_call: {}
+
+jobs:
+ test:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest, macos-latest, windows-latest]
+ python-version: ["3.10", "3.13"]
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install hatch
+ uses: pypa/hatch@install
+
+ - name: Check installation
+ run: hatch run install:check
+
+ - name: Check dependencies
+ run: hatch run audit:check
+ - name: Test suite
+ run: hatch run +py=${{ matrix.python-version }} test:run
+
+ - name: Report coverage
+ shell: bash
+ run: bash <(curl -s https://codecov.io/bash)
diff --git a/.gitignore b/.gitignore
index 7b004e5..b90ccff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,87 @@
+### Linux template
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+### Windows template
+# Windows thumbnail cache files
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+### JupyterNotebooks template
+# gitignore template for Jupyter Notebooks
+# website: http://jupyter.org/
+
+.ipynb_checkpoints
+*/.ipynb_checkpoints/*
+
+# IPython
+profile_default/
+ipython_config.py
+
+# Remove previous ipynb_checkpoints
+# git rm -r .ipynb_checkpoints/
+
+### macOS template
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
@@ -70,17 +154,15 @@ instance/
# Sphinx documentation
docs/_build/
+docs/api
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
-.ipynb_checkpoints
# IPython
-profile_default/
-ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
@@ -94,12 +176,6 @@ ipython_config.py
# install all needed dependencies.
#Pipfile.lock
-# UV
-# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
-# This is especially recommended for binary packages to ensure reproducibility, and is more
-# commonly ignored for libraries.
-#uv.lock
-
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
@@ -112,10 +188,8 @@ ipython_config.py
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
-# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
+# https://pdm.fming.dev/#use-with-ide
.pdm.toml
-.pdm-python
-.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
@@ -167,28 +241,5 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
-# Abstra
-# Abstra is an AI-powered process automation framework.
-# Ignore directories containing user credentials, local state, and settings.
-# Learn more at https://abstra.io/docs
-.abstra/
-
-# Visual Studio Code
-# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
-# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
-# and can be added to the global gitignore or merged into this file. However, if you prefer,
-# you could uncomment the following to ignore the enitre vscode folder
-# .vscode/
-
-# Ruff stuff:
-.ruff_cache/
-
-# PyPI configuration file
-.pypirc
-
-# Cursor
-# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
-# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
-# refer to https://docs.cursor.com/context/ignore-files
-.cursorignore
-.cursorindexingignore
\ No newline at end of file
+# Hatch-VCS
+_version.py
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..c8f40ae
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,14 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+- Upcoming features and fixes
+
+## [0.1.0] - (1979-01-01)
+
+- First release
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..a77211d
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,130 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+- Demonstrating empathy and kindness toward other people
+- Being respectful of differing opinions, viewpoints, and experiences
+- Giving and gracefully accepting constructive feedback
+- Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+- Focusing on what is best not just for us as individuals, but for the
+ overall community
+
+Examples of unacceptable behavior include:
+
+- The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+- Trolling, insulting or derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or email
+ address, without their explicit permission
+- Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+[//]: # (TODO: You need to choose whom and how to contact them.)
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+\[INSERT CONTACT METHOD\].
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
+
+[homepage]: https://www.contributor-covenant.org
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..6cdc7a3
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,106 @@
+# Contributing
+
+Contributions of all kinds are welcome here, and they are greatly appreciated!
+Every little bit helps, and credit will always be given.
+
+## Example Contributions
+
+You can contribute in many ways, for example:
+
+* [Report bugs](#report-bugs)
+* [Fix Bugs](#fix-bugs)
+* [Implement Features](#implement-features)
+* [Write Documentation](#write-documentation)
+* [Submit Feedback](#submit-feedback)
+
+### Report Bugs
+
+Report bugs at https://github.com/montuygl/pyospackage_montuygl/issues.
+
+**If you are reporting a bug, please follow the template guidelines. The more
+detailed your report, the easier and thus faster we can help you.**
+
+### Fix Bugs
+
+Look through the GitHub issues for bugs. Anything labelled with `bug` and
+`help wanted` is open to whoever wants to implement it. When you decide to work on such
+an issue, please assign yourself to it and add a comment that you'll be working on that,
+too. If you see another issue without the `help wanted` label, just post a comment, the
+maintainers are usually happy for any support that they can get.
+
+### Implement Features
+
+Look through the GitHub issues for features. Anything labelled with
+`enhancement` and `help wanted` is open to whoever wants to implement it. As
+for [fixing bugs](#fix-bugs), please assign yourself to the issue and add a comment that
+you'll be working on that, too. If another enhancement catches your fancy, but it
+doesn't have the `help wanted` label, just post a comment, the maintainers are usually
+happy for any support that they can get.
+
+### Write Documentation
+
+pyospackage_montuygl could always use more documentation, whether as
+part of the official documentation, in docstrings, or even on the web in blog
+posts, articles, and such. Just
+[open an issue](https://github.com/montuygl/pyospackage_montuygl/issues)
+to let us know what you will be working on so that we can provide you with guidance.
+
+### Submit Feedback
+
+The best way to send feedback is to file an issue at
+https://github.com/montuygl/pyospackage_montuygl/issues. If your feedback fits the format of one of
+the issue templates, please use that. Remember that this is a volunteer-driven
+project and everybody has limited time.
+
+## Get Started!
+
+Ready to contribute? Here's how to set up pyospackage_montuygl for
+local development.
+
+1. Fork the https://github.com/montuygl/pyospackage_montuygl
+ repository on GitHub.
+2. Clone your fork locally (*if you want to work locally*)
+
+ ```shell
+ git clone git@github.com:your_name_here/pyospackage_montuygl.git
+ ```
+
+3. [Install hatch](https://hatch.pypa.io/latest/install/).
+
+4. Create a branch for local development using the default branch (typically `main`) as a starting point. Use `fix` or `feat` as a prefix for your branch name.
+
+ ```shell
+ git checkout main
+ git checkout -b fix-name-of-your-bugfix
+ ```
+
+ Now you can make your changes locally.
+
+5. When you're done making changes, apply the quality assurance tools and check
+ that your changes pass our test suite. This is all included with tox
+
+ ```shell
+ hatch run test:run
+ ```
+
+6. Commit your changes and push your branch to GitHub. Please use [semantic
+ commit messages](https://www.conventionalcommits.org/).
+
+ ```shell
+ git add .
+ git commit -m "fix: summarize your changes"
+ git push -u origin fix-name-of-your-bugfix
+ ```
+
+7. Open the link displayed in the message when pushing your new branch in order
+ to submit a pull request.
+
+### Pull Request Guidelines
+
+Before you submit a pull request, check that it meets these guidelines:
+
+1. The pull request should include tests.
+2. If the pull request adds functionality, the docs should be updated. Put your
+ new functionality into a function with a docstring.
+3. Your pull request will automatically be checked by the full test suite.
+ It needs to pass all of them before it can be considered for merging.
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
new file mode 100644
index 0000000..8f43da1
--- /dev/null
+++ b/DEVELOPMENT.md
@@ -0,0 +1,229 @@
+# Development Guide
+
+Welcome to your shiny new package. This page will help you get started with using Hatch to manage your package.
+
+If you look at your project, you will see that a `pyproject.toml` file. This file stores both your package configuration and settings for development tools like Hatch that you will use to work on your package.
+
+This file is written using a `.toml` format. [You can learn more about toml here.](https://www.pyopensci.org/python-package-guide/package-structure-code/pyproject-toml-python-package-metadata.html) Here's the TL&DR:
+
+* Each `[]` section in the toml file is called a table.
+* You can nest tables with double brackets like this`[[]]`
+* Tables contain information about a element that you want to configure.
+
+We are using Hatch as the default packaging tool.
+Hatch allows you to configure and run environments and scripts similar to workflow tools like tox or nox.
+
+Hach, by default, uses virtual environments (venv) to manage environments. But you can configure it to use other environment tools.[ Read the hatch documentation to learn more about environments. ](https://hatch.pypa.io/1.13/tutorials/environment/basic-usage/)
+
+For this template, we have set up Hatch environments for you to use. At the bottom of your pyproject.toml file, notice a [hatch environment](https://hatch.pypa.io/1.13/environment/) section that looks like this:
+
+```
+########################################
+# Hatch Environments
+########################################
+```
+
+Below is the Hatch environment to install your package. Notice that it defines pip and twine as two packages that the environment needs.
+
+```toml
+[tool.hatch.envs.build]
+description = """Test the installation the package."""
+dependencies = [
+ "pip",
+ "twine",
+]
+```
+
+The table below defines the scripts that you will run build and check your package.
+
+```toml
+[tool.hatch.envs.build.scripts]
+check = [
+ "pip check",
+ "hatch build {args:--clean}",
+ "twine check dist/*",
+]
+detached = true
+```
+
+You can enter that environment to check it out:
+
+```console
+$ hatch shell build
+```
+
+If you run `pip list`, in the environment, **twine** will be there:
+
+```console
+$ pip list
+```
+
+Hatch by default, installs your package in **editable mode (`-e`)** into its virtual environments. But if `detached=True` is set, then it will skip installing your package into the virtual enviornment.
+
+### Hatch and matrix environments
+
+Below you see the Hatch environment test table.
+
+`tool.hatch.envs` says, "Hey, Hatch, this is the definition for an environment."
+`test` is the name of the environment.
+
+The environment below defines the dependencies that Hatch needs to install into the environment named test.
+
+```toml
+[tool.hatch.envs.test]
+description = """Run the test suite."""
+dependencies = [
+ "pytest",
+ "pytest-cov",
+ "pytest-raises",
+ "pytest-randomly",
+ "pytest-xdist",
+]
+```
+
+To enter a Hatch environment use:
+
+`hatch shell environmentname`
+
+So you can enter the test environment above with:
+
+`hatch shell test`
+
+### Your test environment has a matrix associated with it
+
+If the environment has a matrix associated with it, that tells Hatch to run the test scripts across different Python versions.
+
+```toml
+[[tool.hatch.envs.test.matrix]]
+python = ["3.10", "3.11", "3.12", "3.13"]
+```
+
+If you run `hatch shell test`, you will see the output below. To enter an environment with a matrix attached to it, you need to pick the Python environment version that you want to open.
+
+```console
+$ hatch shell test
+Environment `test` defines a matrix, choose one of the following instead:
+
+test.py3.10
+test.py3.11
+test.py3.12
+test.py3.13
+```
+
+Open the Python 3.13 environment like this:
+
+```console
+$ hatch shell test.py3.13
+```
+
+To leave an environment use:
+
+```console
+$ deactivate
+```
+
+### Hatch scripts
+
+In the tests section of your pyproject.toml, you will see a `tool.hatch.envs.test.scripts` table.
+
+This table defines the commands that you want Hatch to run in the test environment. Notice that the script has one command called `run`.
+
+```toml
+[tool.hatch.envs.test.scripts]
+run = "pytest {args:--cov=greatproject --cov-report=term-missing}"
+```
+
+To run this script , use:
+
+`hatch run test:run`
+
+* `hatch run`: calls Hatch and tells it that it will be running a command
+* `test:run`: defines the environment you want it to run (`test`) and defines the name of the "script" to be`run`.
+
+If you have a Hatch matrix setup for tests, it will both install the necessary Python version using UV and run your tests on each version of the Python versions that you declare in the matrix table. In this case, there are 4 Python versions in the environment, so your tests will run 4 times, once in each Python version listed in the matrix table.
+
+```
+@lwasser ➜ /workspaces/pyopensci-scipy25-create-python-package (main) $ hatch run test:run
+──────────────────────────────────────────────────────────────────────── test.py3.10 ────────────────────────────────────────────────────────────────────────
+==================================================================== test session starts ====================================================================
+platform linux -- Python 3.10.16, pytest-8.4.1, pluggy-1.6.0
+Using --randomly-seed=1490740387
+rootdir: /workspaces/pyopensci-scipy25-create-python-package
+configfile: pyproject.toml
+testpaths: tests
+plugins: xdist-3.8.0, randomly-3.16.0, raises-0.11, cov-6.2.1
+collected 2 items
+
+tests/system/test_import.py . [ 50%]
+tests/unit/test_example.py . [100%]
+
+====================================================================== tests coverage =======================================================================
+_____________________________________________________ coverage: platform linux, python 3.10.16-final-0 ______________________________________________________
+
+Name Stmts Miss Branch BrPart Cover Missing
+----------------------------------------------------------------------------
+src/greatproject/__init__.py 0 0 0 0 100.00%
+src/greatproject/example.py 2 0 0 0 100.00%
+----------------------------------------------------------------------------
+TOTAL 2 0 0 0 100.00%
+===================================================================== 2 passed in 0.05s =====================================================================
+──────────────────────────────────────────────────────────────────────── test.py3.11 ────────────────────────────────────────────────────────────────────────
+==================================================================== test session starts ====================================================================
+platform linux -- Python 3.11.12, pytest-8.4.1, pluggy-1.6.0
+Using --randomly-seed=1596865075
+rootdir: /workspaces/pyopensci-scipy25-create-python-package
+configfile: pyproject.toml
+testpaths: tests
+plugins: xdist-3.8.0, randomly-3.16.0, raises-0.11, cov-6.2.1
+collected 2 items
+
+tests/system/test_import.py . [ 50%]
+tests/unit/test_example.py . [100%]
+
+====================================================================== tests coverage =======================================================================
+_____________________________________________________ coverage: platform linux, python 3.11.12-final-0 ______________________________________________________
+
+Name Stmts Miss Branch BrPart Cover Missing
+----------------------------------------------------------------------------
+src/greatproject/__init__.py 0 0 0 0 100.00%
+src/greatproject/example.py 2 0 0 0 100.00%
+----------------------------------------------------------------------------
+TOTAL 2 0 0 0 100.00%
+===================================================================== 2 passed in 0.05s =====================================================================
+```
+
+## Build your package
+
+You can build your package using the environment and scripts defined in the `build` tables:
+
+`hatch run build:check`
+
+This script builds and checks the output distribution files of your package.
+
+This build environment table declares that `pip` and `twine` should be added to that environment. Adding pip to the environment ensures that it is a current, up-to-date version.
+
+```toml
+[tool.hatch.envs.build]
+description = """Build and test your package."""
+dependencies = [
+ "pip",
+ "twine",
+]
+detached = true
+```
+
+```toml
+# This table installs created the command hatch run install:check which will build and check your package.
+[tool.hatch.envs.install.scripts]
+check = [
+ "pip check",
+ "hatch build {args:--clean}",
+ "twine check dist/*",
+]
+```
+This uses the above environment and tells hatch to run
+
+* `pip check`, # verifies your dependencies
+* `hatch build --clean`
+* `twine check dist/*` # this checks your distribution for metadata and other potential issues.
+to build and test your package.
diff --git a/LICENSE b/LICENSE
index 046d4c4..d58eeb4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,28 +1,21 @@
-BSD 3-Clause License
+MIT License
-Copyright (c) 2025, pyOpenSci
+Copyright (c) 2025 Gerald Montuya
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
+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:
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+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/README.md b/README.md
index c7bfa04..da42249 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,33 @@
-#
SciPy 2025 workshop: Create a Python Package
+# Welcome to pyospackage_montuygl
-This workshop is developed for the [pyOpenSci in-person packaging workshop at the
-SciPy meeting in Tacoma, Washington 2025](https://cfp.scipy.org/scipy2025/talk/Z3VBWR/).
+| | |
+|--------|--------|
+| Package | [](https://pypi.org/project/pyospackage_montuygl/) [](https://pypi.org/project/pyospackage_montuygl/) |
+| Meta | [](CODE_OF_CONDUCT.md) |
-## Getting started
-Before the workshop, be sure that you read our setup instructions on our [events
-page here](https://www.pyopensci.org/events/pyopensci-scipy25-create-python-package-workshop.html).
+*TODO: the above badges that indicate python version and package version will only work if your package is on PyPI.
+If you don't plan to publish to PyPI, you can remove them.*
-You will need a GitHub and a testPyPI account to follow along.
+pyospackage_montuygl is a project that (describe what it does here).
-## GitHub Codespaces
+## Get started
-We have GitHub Codespaces configured for this workshop. To be successful during
-the workshop, we suggest that you fork and open a codespace prior to attending
-the workshop to ensure the enviornment loads properly. The initial codespace build can take up to 15 minutes.
+You can install this package into your preferred Python environment using pip:
-The link above provides you with instructions
-one how to do this and how to setup the accounts you need for the workshop.
+```bash
+$ pip install pyospackage_montuygl
+```
-## Creating your package
+TODO: Add a brief example of how to use the package to this section
-To use the copier template, follow the [tutorial here](https://www.pyopensci.org/python-package-guide/tutorials/create-python-package.html) that walks you through the steps.
-The command to run the copier template is:
+To use pyospackage_montuygl in your code:
-`copier copy gh:pyopensci/pyos-package-template .`
+```python
+>>> import pyospackage_montuygl
+>>> pyospackage_montuygl.hello_world()
+```
+
+## Copyright
+
+- Copyright © 2025 Gerald Montuya.
+- Free software distributed under the [MIT License](./LICENSE).
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..e3654ef
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,99 @@
+#
+# pyospackage_montuygl documentation build configuration file
+#
+import importlib.metadata
+
+# -- General configuration -----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+ "myst_parser",
+ "sphinx.ext.intersphinx",
+ "sphinx.ext.autodoc",
+]
+
+# The suffix of source filenames.
+source_suffix = ".rst"
+
+# The master toctree document.
+master_doc = "index"
+
+# General information about the project.
+project = "pyospackage_montuygl"
+copyright = "Copyright © 2025 Gerald Montuya"
+html_show_sphinx = False
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+try:
+ version = importlib.metadata.version("pyospackage_montuygl")
+except importlib.metadata.PackageNotFoundError:
+ version = "0.0.0"
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = "default"
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = "en"
+
+# -- Options for extensions ----------------------------------------------------
+# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html
+myst_enable_extensions = ["html_image"]
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+html_theme = "pydata_sphinx_theme"
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# " v documentation".
+# html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+# html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+# html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+# html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+# html_static_path = ['_static']
+
+# Custom sidebar templates, maps document names to template names.
+# html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+# html_additional_pages = {}
+
+# If true, links to the reST sources are added to the pages.
+# html_show_sourcelink = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+# html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+# html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = "pyospackage_montuygl_doc"
+
+
+intersphinx_mapping = {
+ "python": ("https://docs.python.org/", None),
+}
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..cb0de02
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,17 @@
+# pyospackage_montuygl
+
+## Overview
+
+A package that adds numbers together.
+
+[API Documentation](./api/modules.rst)
+
+## Copyright
+
+- Copyright © 2025 Gerald Montuya.
+- Free software distributed under the MIT License.
+
+```{toctree}
+:hidden:
+./api/modules.rst
+```
diff --git a/myvenv/bin/Activate.ps1 b/myvenv/bin/Activate.ps1
new file mode 100644
index 0000000..b49d77b
--- /dev/null
+++ b/myvenv/bin/Activate.ps1
@@ -0,0 +1,247 @@
+<#
+.Synopsis
+Activate a Python virtual environment for the current PowerShell session.
+
+.Description
+Pushes the python executable for a virtual environment to the front of the
+$Env:PATH environment variable and sets the prompt to signify that you are
+in a Python virtual environment. Makes use of the command line switches as
+well as the `pyvenv.cfg` file values present in the virtual environment.
+
+.Parameter VenvDir
+Path to the directory that contains the virtual environment to activate. The
+default value for this is the parent of the directory that the Activate.ps1
+script is located within.
+
+.Parameter Prompt
+The prompt prefix to display when this virtual environment is activated. By
+default, this prompt is the name of the virtual environment folder (VenvDir)
+surrounded by parentheses and followed by a single space (ie. '(.venv) ').
+
+.Example
+Activate.ps1
+Activates the Python virtual environment that contains the Activate.ps1 script.
+
+.Example
+Activate.ps1 -Verbose
+Activates the Python virtual environment that contains the Activate.ps1 script,
+and shows extra information about the activation as it executes.
+
+.Example
+Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
+Activates the Python virtual environment located in the specified location.
+
+.Example
+Activate.ps1 -Prompt "MyPython"
+Activates the Python virtual environment that contains the Activate.ps1 script,
+and prefixes the current prompt with the specified string (surrounded in
+parentheses) while the virtual environment is active.
+
+.Notes
+On Windows, it may be required to enable this Activate.ps1 script by setting the
+execution policy for the user. You can do this by issuing the following PowerShell
+command:
+
+PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
+
+For more information on Execution Policies:
+https://go.microsoft.com/fwlink/?LinkID=135170
+
+#>
+Param(
+ [Parameter(Mandatory = $false)]
+ [String]
+ $VenvDir,
+ [Parameter(Mandatory = $false)]
+ [String]
+ $Prompt
+)
+
+<# Function declarations --------------------------------------------------- #>
+
+<#
+.Synopsis
+Remove all shell session elements added by the Activate script, including the
+addition of the virtual environment's Python executable from the beginning of
+the PATH variable.
+
+.Parameter NonDestructive
+If present, do not remove this function from the global namespace for the
+session.
+
+#>
+function global:deactivate ([switch]$NonDestructive) {
+ # Revert to original values
+
+ # The prior prompt:
+ if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
+ Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
+ Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
+ }
+
+ # The prior PYTHONHOME:
+ if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
+ Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
+ Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
+ }
+
+ # The prior PATH:
+ if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
+ Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
+ Remove-Item -Path Env:_OLD_VIRTUAL_PATH
+ }
+
+ # Just remove the VIRTUAL_ENV altogether:
+ if (Test-Path -Path Env:VIRTUAL_ENV) {
+ Remove-Item -Path env:VIRTUAL_ENV
+ }
+
+ # Just remove VIRTUAL_ENV_PROMPT altogether.
+ if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
+ Remove-Item -Path env:VIRTUAL_ENV_PROMPT
+ }
+
+ # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
+ if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
+ Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
+ }
+
+ # Leave deactivate function in the global namespace if requested:
+ if (-not $NonDestructive) {
+ Remove-Item -Path function:deactivate
+ }
+}
+
+<#
+.Description
+Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
+given folder, and returns them in a map.
+
+For each line in the pyvenv.cfg file, if that line can be parsed into exactly
+two strings separated by `=` (with any amount of whitespace surrounding the =)
+then it is considered a `key = value` line. The left hand string is the key,
+the right hand is the value.
+
+If the value starts with a `'` or a `"` then the first and last character is
+stripped from the value before being captured.
+
+.Parameter ConfigDir
+Path to the directory that contains the `pyvenv.cfg` file.
+#>
+function Get-PyVenvConfig(
+ [String]
+ $ConfigDir
+) {
+ Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
+
+ # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
+ $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
+
+ # An empty map will be returned if no config file is found.
+ $pyvenvConfig = @{ }
+
+ if ($pyvenvConfigPath) {
+
+ Write-Verbose "File exists, parse `key = value` lines"
+ $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
+
+ $pyvenvConfigContent | ForEach-Object {
+ $keyval = $PSItem -split "\s*=\s*", 2
+ if ($keyval[0] -and $keyval[1]) {
+ $val = $keyval[1]
+
+ # Remove extraneous quotations around a string value.
+ if ("'""".Contains($val.Substring(0, 1))) {
+ $val = $val.Substring(1, $val.Length - 2)
+ }
+
+ $pyvenvConfig[$keyval[0]] = $val
+ Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
+ }
+ }
+ }
+ return $pyvenvConfig
+}
+
+
+<# Begin Activate script --------------------------------------------------- #>
+
+# Determine the containing directory of this script
+$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
+$VenvExecDir = Get-Item -Path $VenvExecPath
+
+Write-Verbose "Activation script is located in path: '$VenvExecPath'"
+Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
+Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
+
+# Set values required in priority: CmdLine, ConfigFile, Default
+# First, get the location of the virtual environment, it might not be
+# VenvExecDir if specified on the command line.
+if ($VenvDir) {
+ Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
+}
+else {
+ Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
+ $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
+ Write-Verbose "VenvDir=$VenvDir"
+}
+
+# Next, read the `pyvenv.cfg` file to determine any required value such
+# as `prompt`.
+$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
+
+# Next, set the prompt from the command line, or the config file, or
+# just use the name of the virtual environment folder.
+if ($Prompt) {
+ Write-Verbose "Prompt specified as argument, using '$Prompt'"
+}
+else {
+ Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
+ if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
+ Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
+ $Prompt = $pyvenvCfg['prompt'];
+ }
+ else {
+ Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
+ Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
+ $Prompt = Split-Path -Path $venvDir -Leaf
+ }
+}
+
+Write-Verbose "Prompt = '$Prompt'"
+Write-Verbose "VenvDir='$VenvDir'"
+
+# Deactivate any currently active virtual environment, but leave the
+# deactivate function in place.
+deactivate -nondestructive
+
+# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
+# that there is an activated venv.
+$env:VIRTUAL_ENV = $VenvDir
+
+if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
+
+ Write-Verbose "Setting prompt to '$Prompt'"
+
+ # Set the prompt to include the env name
+ # Make sure _OLD_VIRTUAL_PROMPT is global
+ function global:_OLD_VIRTUAL_PROMPT { "" }
+ Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
+ New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
+
+ function global:prompt {
+ Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
+ _OLD_VIRTUAL_PROMPT
+ }
+ $env:VIRTUAL_ENV_PROMPT = $Prompt
+}
+
+# Clear PYTHONHOME
+if (Test-Path -Path Env:PYTHONHOME) {
+ Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
+ Remove-Item -Path Env:PYTHONHOME
+}
+
+# Add the venv to the PATH
+Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
+$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
diff --git a/myvenv/bin/activate b/myvenv/bin/activate
new file mode 100644
index 0000000..434523f
--- /dev/null
+++ b/myvenv/bin/activate
@@ -0,0 +1,76 @@
+# This file must be used with "source bin/activate" *from bash*
+# You cannot run it directly
+
+deactivate () {
+ # reset old environment variables
+ if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
+ PATH="${_OLD_VIRTUAL_PATH:-}"
+ export PATH
+ unset _OLD_VIRTUAL_PATH
+ fi
+ if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
+ PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
+ export PYTHONHOME
+ unset _OLD_VIRTUAL_PYTHONHOME
+ fi
+
+ # Call hash to forget past locations. Without forgetting
+ # past locations the $PATH changes we made may not be respected.
+ # See "man bash" for more details. hash is usually a builtin of your shell
+ hash -r 2> /dev/null
+
+ if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
+ PS1="${_OLD_VIRTUAL_PS1:-}"
+ export PS1
+ unset _OLD_VIRTUAL_PS1
+ fi
+
+ unset VIRTUAL_ENV
+ unset VIRTUAL_ENV_PROMPT
+ if [ ! "${1:-}" = "nondestructive" ] ; then
+ # Self destruct!
+ unset -f deactivate
+ fi
+}
+
+# unset irrelevant variables
+deactivate nondestructive
+
+# on Windows, a path can contain colons and backslashes and has to be converted:
+case "$(uname)" in
+ CYGWIN*|MSYS*|MINGW*)
+ # transform D:\path\to\venv to /d/path/to/venv on MSYS and MINGW
+ # and to /cygdrive/d/path/to/venv on Cygwin
+ VIRTUAL_ENV=$(cygpath /workspaces/pyopensci-scipy25-create-python-package/myvenv)
+ export VIRTUAL_ENV
+ ;;
+ *)
+ # use the path as-is
+ export VIRTUAL_ENV=/workspaces/pyopensci-scipy25-create-python-package/myvenv
+ ;;
+esac
+
+_OLD_VIRTUAL_PATH="$PATH"
+PATH="$VIRTUAL_ENV/"bin":$PATH"
+export PATH
+
+VIRTUAL_ENV_PROMPT='(myvenv) '
+export VIRTUAL_ENV_PROMPT
+
+# unset PYTHONHOME if set
+# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
+# could use `if (set -u; : $PYTHONHOME) ;` in bash
+if [ -n "${PYTHONHOME:-}" ] ; then
+ _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
+ unset PYTHONHOME
+fi
+
+if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
+ _OLD_VIRTUAL_PS1="${PS1:-}"
+ PS1="("'(myvenv) '") ${PS1:-}"
+ export PS1
+fi
+
+# Call hash to forget past commands. Without forgetting
+# past commands the $PATH changes we made may not be respected
+hash -r 2> /dev/null
diff --git a/myvenv/bin/activate.csh b/myvenv/bin/activate.csh
new file mode 100644
index 0000000..6199612
--- /dev/null
+++ b/myvenv/bin/activate.csh
@@ -0,0 +1,27 @@
+# This file must be used with "source bin/activate.csh" *from csh*.
+# You cannot run it directly.
+
+# Created by Davide Di Blasi .
+# Ported to Python 3.3 venv by Andrew Svetlov
+
+alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
+
+# Unset irrelevant variables.
+deactivate nondestructive
+
+setenv VIRTUAL_ENV /workspaces/pyopensci-scipy25-create-python-package/myvenv
+
+set _OLD_VIRTUAL_PATH="$PATH"
+setenv PATH "$VIRTUAL_ENV/"bin":$PATH"
+
+
+set _OLD_VIRTUAL_PROMPT="$prompt"
+
+if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
+ set prompt = '(myvenv) '"$prompt"
+ setenv VIRTUAL_ENV_PROMPT '(myvenv) '
+endif
+
+alias pydoc python -m pydoc
+
+rehash
diff --git a/myvenv/bin/activate.fish b/myvenv/bin/activate.fish
new file mode 100644
index 0000000..f1a5a21
--- /dev/null
+++ b/myvenv/bin/activate.fish
@@ -0,0 +1,69 @@
+# This file must be used with "source /bin/activate.fish" *from fish*
+# (https://fishshell.com/). You cannot run it directly.
+
+function deactivate -d "Exit virtual environment and return to normal shell environment"
+ # reset old environment variables
+ if test -n "$_OLD_VIRTUAL_PATH"
+ set -gx PATH $_OLD_VIRTUAL_PATH
+ set -e _OLD_VIRTUAL_PATH
+ end
+ if test -n "$_OLD_VIRTUAL_PYTHONHOME"
+ set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
+ set -e _OLD_VIRTUAL_PYTHONHOME
+ end
+
+ if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
+ set -e _OLD_FISH_PROMPT_OVERRIDE
+ # prevents error when using nested fish instances (Issue #93858)
+ if functions -q _old_fish_prompt
+ functions -e fish_prompt
+ functions -c _old_fish_prompt fish_prompt
+ functions -e _old_fish_prompt
+ end
+ end
+
+ set -e VIRTUAL_ENV
+ set -e VIRTUAL_ENV_PROMPT
+ if test "$argv[1]" != "nondestructive"
+ # Self-destruct!
+ functions -e deactivate
+ end
+end
+
+# Unset irrelevant variables.
+deactivate nondestructive
+
+set -gx VIRTUAL_ENV /workspaces/pyopensci-scipy25-create-python-package/myvenv
+
+set -gx _OLD_VIRTUAL_PATH $PATH
+set -gx PATH "$VIRTUAL_ENV/"bin $PATH
+
+# Unset PYTHONHOME if set.
+if set -q PYTHONHOME
+ set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
+ set -e PYTHONHOME
+end
+
+if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
+ # fish uses a function instead of an env var to generate the prompt.
+
+ # Save the current fish_prompt function as the function _old_fish_prompt.
+ functions -c fish_prompt _old_fish_prompt
+
+ # With the original prompt function renamed, we can override with our own.
+ function fish_prompt
+ # Save the return status of the last command.
+ set -l old_status $status
+
+ # Output the venv prompt; color taken from the blue of the Python logo.
+ printf "%s%s%s" (set_color 4B8BBE) '(myvenv) ' (set_color normal)
+
+ # Restore the return status of the previous command.
+ echo "exit $old_status" | .
+ # Output the original/"old" prompt.
+ _old_fish_prompt
+ end
+
+ set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
+ set -gx VIRTUAL_ENV_PROMPT '(myvenv) '
+end
diff --git a/myvenv/bin/pip b/myvenv/bin/pip
new file mode 100755
index 0000000..274e498
--- /dev/null
+++ b/myvenv/bin/pip
@@ -0,0 +1,8 @@
+#!/workspaces/pyopensci-scipy25-create-python-package/myvenv/bin/python
+# -*- coding: utf-8 -*-
+import re
+import sys
+from pip._internal.cli.main import main
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/myvenv/bin/pip3 b/myvenv/bin/pip3
new file mode 100755
index 0000000..274e498
--- /dev/null
+++ b/myvenv/bin/pip3
@@ -0,0 +1,8 @@
+#!/workspaces/pyopensci-scipy25-create-python-package/myvenv/bin/python
+# -*- coding: utf-8 -*-
+import re
+import sys
+from pip._internal.cli.main import main
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/myvenv/bin/pip3.12 b/myvenv/bin/pip3.12
new file mode 100755
index 0000000..274e498
--- /dev/null
+++ b/myvenv/bin/pip3.12
@@ -0,0 +1,8 @@
+#!/workspaces/pyopensci-scipy25-create-python-package/myvenv/bin/python
+# -*- coding: utf-8 -*-
+import re
+import sys
+from pip._internal.cli.main import main
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/myvenv/bin/python b/myvenv/bin/python
new file mode 120000
index 0000000..dd402d5
--- /dev/null
+++ b/myvenv/bin/python
@@ -0,0 +1 @@
+/opt/conda/bin/python
\ No newline at end of file
diff --git a/myvenv/bin/python3 b/myvenv/bin/python3
new file mode 120000
index 0000000..d8654aa
--- /dev/null
+++ b/myvenv/bin/python3
@@ -0,0 +1 @@
+python
\ No newline at end of file
diff --git a/myvenv/bin/python3.12 b/myvenv/bin/python3.12
new file mode 120000
index 0000000..d8654aa
--- /dev/null
+++ b/myvenv/bin/python3.12
@@ -0,0 +1 @@
+python
\ No newline at end of file
diff --git a/myvenv/lib64 b/myvenv/lib64
new file mode 120000
index 0000000..7951405
--- /dev/null
+++ b/myvenv/lib64
@@ -0,0 +1 @@
+lib
\ No newline at end of file
diff --git a/myvenv/pyvenv.cfg b/myvenv/pyvenv.cfg
new file mode 100644
index 0000000..6d0f819
--- /dev/null
+++ b/myvenv/pyvenv.cfg
@@ -0,0 +1,5 @@
+home = /opt/conda/bin
+include-system-site-packages = false
+version = 3.12.10
+executable = /opt/conda/bin/python3.12
+command = /opt/conda/bin/python -m venv /workspaces/pyopensci-scipy25-create-python-package/myvenv
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..8b7d7dc
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,163 @@
+################################################################################
+# Build Configuration
+################################################################################
+
+[build-system]
+build-backend = "hatchling.build"
+requires = ["hatchling"]
+
+################################################################################
+# Project Configuration
+################################################################################
+
+[project]
+name = "pyospackage_montuygl"
+# You can chose to use dynamic versioning with hatch or static where you add it manually.
+version = "0.1.0"
+
+description = "A package that adds numbers together."
+authors = [
+ { name = "Gerald Montuya", email = "fakeemail@fakeemail.com" },
+]
+license = "MIT"
+requires-python = ">= 3.10" # Adjust based on the minimum version of Python that you support
+readme = {"file" = "README.md", "content-type" = "text/markdown"}
+# Please consult https://pypi.org/classifiers/ for a full list.
+classifiers = [
+ "Development Status :: 2 - Pre-Alpha",
+ "Intended Audience :: Science/Research",
+ "License :: OSI Approved :: MIT License",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3 :: Only",
+]
+
+keywords = ["numerical data", "analysis"]
+
+dependencies = ["numpy", "scikit-learn"]
+
+[project.urls]
+Homepage = "https://github.com/montuygl/pyospackage_montuygl"
+"Source Code" = "https://github.com/montuygl/pyospackage_montuygl"
+"Bug Tracker" = "https://github.com/montuygl/pyospackage_montuygl/issues"
+Documentation = "https://pyospackage_montuygl.readthedocs.io"
+Download = "https://pypi.org/project/pyospackage_montuygl/#files"
+
+[project.optional-dependencies]
+dev = [
+ "hatch",
+ "pre-commit",
+]
+################################################################################
+# Tool Configuration
+################################################################################
+
+# Hatch is building your package's wheel and sdist
+# This tells hatch to only include Python packages (i.e., folders with __init__.py) in the build.
+# read more about package building, here:
+# https://www.pyopensci.org/python-package-guide/package-structure-code/python-package-distribution-files-sdist-wheel.html
+[tool.hatch.build]
+only-packages = true
+
+# This tells Hatch to build the package from the src/me directory.
+# Read more about src layouts here: https://www.pyopensci.org/python-package-guide/package-structure-code/python-package-structure.html
+[tool.hatch.build.targets.wheel]
+packages = ["src/pyospackage_montuygl"]
+
+######## Configure pytest for your test suite ########
+[tool.pytest.ini_options]
+testpaths = ["tests"] # Tells pytest what directory tests are in
+markers = ["raises"] # Tells pytest to not raise a warning if you use @pytest.mark.raises
+
+[tool.coverage.paths]
+source = [
+ "src/pyospackage_montuygl",
+ "*/site-packages/pyospackage_montuygl",
+]
+
+[tool.coverage.run]
+# Ensures code coverage is measured for branches (conditional statements with different outcomes) in your code.
+branch = true
+parallel = true
+
+[tool.coverage.report]
+# This configures the output test coverage report
+exclude_lines = ["pragma: no cover"]
+precision = 2
+
+# Use UV to create Hatch environments
+[tool.hatch.envs.default]
+installer = "uv"
+################################################################################
+# Hatch Environments
+################################################################################
+
+#--------------- Build and check your package ---------------#
+
+# This table installs the tools you need to test and build your package
+[tool.hatch.envs.build]
+description = """Test the installation the package."""
+dependencies = [
+ "pip",
+ "twine",
+]
+detached = true
+
+# This table installs created the command hatch run install:check which will build and check your package.
+[tool.hatch.envs.build.scripts]
+check = [
+ "pip check",
+ "hatch build {args:--clean}",
+ "twine check dist/*",
+]
+
+#--------------- Run tests ---------------#
+
+
+[tool.hatch.envs.test]
+description = """Run the test suite."""
+extra-dependencies = [
+ "pytest",
+ "pytest-cov",
+ "pytest-raises",
+ "pytest-randomly",
+ "pytest-xdist",
+]
+
+[[tool.hatch.envs.test.matrix]]
+python = ["3.10", "3.11", "3.12", "3.13"]
+
+[tool.hatch.envs.test.scripts]
+run = "pytest {args:--cov=pyospackage_montuygl --cov-report=term-missing}"
+
+#--------------- Build and preview your documentation ---------------#
+
+# This sets up a hatch environment with associated dependencies that need to be installed
+[tool.hatch.envs.docs]
+description = """Build or serve the documentation."""
+python = "3.10"
+dependencies = [
+ "pydata_sphinx_theme ~=0.16",
+ "myst-parser ~=4.0",
+ "Sphinx ~=8.0",
+ "sphinx-autobuild ==2024.10.3"
+]
+
+# This table contains the scripts that you can use to build and serve your docs
+# hatch run docs:build will build your documentation
+# hatch run docs:serve will serve them 'live' on your computer locally
+[tool.hatch.envs.docs.scripts]
+build = ["sphinx-apidoc -o docs/api src/pyospackage_montuygl", "sphinx-build {args:-W -b html docs docs/_build}"]
+serve = ["sphinx-apidoc -o docs/api src/pyospackage_montuygl", "sphinx-autobuild docs --watch src/pyospackage_montuygl {args:-b html docs/_build/serve}"]
+
+#--------------- Check security for your dependencies ---------------#
+
+[tool.hatch.envs.audit]
+description = """Check dependencies for security vulnerabilities."""
+extra-dependencies = [
+ "pip-audit",
+]
+
+[tool.hatch.envs.audit.scripts]
+check = ["pip-audit"]
+
+#--------------- Typing ---------------#
diff --git a/src/pyospackage_montuygl/__init__.py b/src/pyospackage_montuygl/__init__.py
new file mode 100644
index 0000000..0864ff9
--- /dev/null
+++ b/src/pyospackage_montuygl/__init__.py
@@ -0,0 +1,31 @@
+# MIT License
+#
+# Copyright (c) 2025 Gerald Montuya
+#
+# 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 (including the next
+# paragraph) 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.
+
+"""
+Add a docstring here for the init module.
+
+This might include a very brief description of the package,
+its purpose, and any important notes.
+"""
+
+from .example import add_numbers
\ No newline at end of file
diff --git a/src/pyospackage_montuygl/example.py b/src/pyospackage_montuygl/example.py
new file mode 100644
index 0000000..e2d2cac
--- /dev/null
+++ b/src/pyospackage_montuygl/example.py
@@ -0,0 +1,36 @@
+"""
+A module that adds numbers together.
+
+You may want to delete this module or modify it for your package.
+It's generally good practice to have a docstring
+that explains the purpose of the module, at the top.
+"""
+
+def add_numbers(a: float, b: float) -> float:
+ """
+ Add two numbers together and return the result.
+
+ This is an example function with a numpy style docstring.
+ We recommend using this style for consistency and readability.
+
+ Parameters
+ ----------
+ a : float
+ The first number to add.
+ b : float
+ The second number to add.
+
+ Returns
+ -------
+ float
+ The sum of the two numbers.
+
+ Examples
+ --------
+ >>> add_numbers(3, 5)
+ 8
+ >>> add_numbers(-2, 7)
+ 5
+
+ """
+ return a + b
diff --git a/tests/unit/test_example.py b/tests/unit/test_example.py
new file mode 100644
index 0000000..00a109c
--- /dev/null
+++ b/tests/unit/test_example.py
@@ -0,0 +1,20 @@
+"""
+A test module that tests your example module.
+
+Some people prefer to write tests in a test file for each function or
+method/ class. Others prefer to write tests for each module. That decision
+is up to you. This test example provides a single test for the example.py
+module.
+"""
+
+from pyospackage_montuygl.example import add_numbers
+
+def test_add_numbers():
+ """
+ Test that add_numbers works as expected.
+
+ A single line docstring for tests is generally sufficient.
+ """
+ out = add_numbers(1, 2)
+ expected_out = 3
+ assert out == expected_out, f"Expected {expected_out} but got {out}"