diff --git a/README.md b/README.md deleted file mode 100644 index d2365c4..0000000 --- a/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# coverage-rich - -[![PyPI - Version](https://img.shields.io/pypi/v/coverage-rich.svg)](https://pypi.org/project/coverage-rich) -[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/coverage-rich.svg)](https://pypi.org/project/coverage-rich) - ------ - -**Table of Contents** - -- [Installation](#installation) -- [License](#license) - -## Installation - -```console -pip install coverage-rich -``` - -## License - -`coverage-rich` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license. diff --git a/copier.yml b/copier.yml new file mode 100644 index 0000000..205835c --- /dev/null +++ b/copier.yml @@ -0,0 +1,12 @@ +_min_copier_version: v6.0.0b0 +package_title_input: + type: str +package_title: + type: str + default: "{{ package_title_input.replace('-', ' ').replace('_', '-').title() }}" +package_name: "{{ package_title.replace(' ', '-').replace('_', '-').lower() }}" +python_package: "{{ package_name.replace(' ', '_').replace('-', '_').lower() }}" +author_name: Waylon Walker +author_github: waylonwalker +description: +_answers_file: .{{package_name}}-copier-answers.yml diff --git a/coverage_rich/cli/__init__.py b/coverage_rich/cli/__init__.py deleted file mode 100644 index 91fe2d5..0000000 --- a/coverage_rich/cli/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: 2023-present Waylon S. Walker -# -# SPDX-License-Identifier: MIT -import click - -from ..__about__ import __version__ - - -@click.group(context_settings={'help_option_names': ['-h', '--help']}, invoke_without_command=True) -@click.version_option(version=__version__, prog_name='coverage-rich') -@click.pass_context -def coverage_rich(ctx: click.Context): - click.echo('Hello world!') diff --git a/{{ package_name }}/.gitignore b/{{ package_name }}/.gitignore new file mode 100644 index 0000000..19e0f43 --- /dev/null +++ b/{{ package_name }}/.gitignore @@ -0,0 +1,961 @@ +# Created by https://www.toptal.com/developers/gitignore/api/vim,node,data,emacs,python,pycharm,executable,sublimetext,visualstudio,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=vim,node,data,emacs,python,pycharm,executable,sublimetext,visualstudio,visualstudiocode + +### Data ### +*.csv +*.dat +*.efx +*.gbr +*.key +*.pps +*.ppt +*.pptx +*.sdf +*.tax2010 +*.vcf +*.xml + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +### Executable ### +*.app +*.bat +*.cgi +*.com +*.exe +*.gadget +*.jar +*.pif +*.vb +*.wsf + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### PyCharm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +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.* +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# 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 +# intended to run in multiple environments; otherwise, check them in: +# .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 + +# 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 +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#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/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.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/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +### SublimeText ### +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + +# SFTP configuration file +sftp-config.json +sftp-config-alt*.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +*.code-workspace + +# Local History for Visual Studio Code + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + +### VisualStudio Patch ### +# Additional files built by Visual Studio + +# End of https://www.toptal.com/developers/gitignore/api/vim,node,data,emacs,python,pycharm,executable,sublimetext,visualstudio,visualstudiocode diff --git a/{{ package_name }}/CHANGELOG.md b/{{ package_name }}/CHANGELOG.md new file mode 100644 index 0000000..eb014a6 --- /dev/null +++ b/{{ package_name }}/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.0 + +init diff --git a/LICENSE.txt b/{{ package_name }}/LICENSE.txt similarity index 100% rename from LICENSE.txt rename to {{ package_name }}/LICENSE.txt diff --git a/{{ package_name }}/README.md b/{{ package_name }}/README.md new file mode 100644 index 0000000..41df047 --- /dev/null +++ b/{{ package_name }}/README.md @@ -0,0 +1,21 @@ +# {{ package_title }} + +[![PyPI - Version](https://img.shields.io/pypi/v/{{ package_name }}.svg)](https://pypi.org/project/{{ package_name }}) +[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/{{ package_name }}.svg)](https://pypi.org/project/{{ package_name }}) + +--- + +**Table of Contents** + +- [Installation](#installation) +- [License](#license) + +## Installation + +```console +pip install {{ package_name }} +``` + +## License + +`{{ package_name }}` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license. diff --git a/{{ package_name }}/copier.yml b/{{ package_name }}/copier.yml new file mode 100644 index 0000000..205835c --- /dev/null +++ b/{{ package_name }}/copier.yml @@ -0,0 +1,12 @@ +_min_copier_version: v6.0.0b0 +package_title_input: + type: str +package_title: + type: str + default: "{{ package_title_input.replace('-', ' ').replace('_', '-').title() }}" +package_name: "{{ package_title.replace(' ', '-').replace('_', '-').lower() }}" +python_package: "{{ package_name.replace(' ', '_').replace('-', '_').lower() }}" +author_name: Waylon Walker +author_github: waylonwalker +description: +_answers_file: .{{package_name}}-copier-answers.yml diff --git a/pyproject.toml b/{{ package_name }}/pyproject.toml.jinja similarity index 54% rename from pyproject.toml rename to {{ package_name }}/pyproject.toml.jinja index 71fb1d7..145c53e 100644 --- a/pyproject.toml +++ b/{{ package_name }}/pyproject.toml.jinja @@ -3,7 +3,7 @@ requires = ["hatchling"] build-backend = "hatchling.build" [project] -name = "coverage-rich" +name = "{{ package_name }}" description = 'A rich terminal report for coveragepy.' readme = "README.md" requires-python = ">=3.7" @@ -24,29 +24,51 @@ classifiers = [ "Programming Language :: Python :: Implementation :: PyPy", ] dependencies = [ - "click", + "rich", + "textual", + "typer", + "anyconfig" ] dynamic = ["version"] [project.urls] -Documentation = "https://github.com/unknown/coverage-rich#readme" -Issues = "https://github.com/unknown/coverage-rich/issues" -Source = "https://github.com/unknown/coverage-rich" +Documentation = "https://github.com/waylonwalker/{{ package_name }}#readme" +Issues = "https://github.com/waylonwalker/{{ package_name }}/issues" +Source = "https://github.com/waylonwalker/{{ package_name }}" +Changelog = "https://github.com/waylonwalker/{{ package_name }}" [project.scripts] -coverage-rich = "coverage_rich.cli:coverage_rich" +{{ package_name }} = "{{ python_package }}.cli.app:app" [tool.hatch.version] -path = "coverage_rich/__about__.py" +path = "{{ python_package }}/__about__.py" [tool.hatch.envs.default] dependencies = [ + "ipython", + "mypy", + "pyflyby", "pytest", "pytest-cov", + "pytest-mock", + "pytest-rich", + "ruff", + "black", ] [tool.hatch.envs.default.scripts] -cov = "pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=coverage_rich --cov=tests {args}" -no-cov = "cov --no-cov {args}" +test = "coverage run -m pytest" +cov = "coverage-rich" +lint = "ruff {{ python_package }}" +format = "black {{ python_package }}" +format-check = "black --check {{ python_package }}" +build-docs = "markata build" +lint-test = [ + "lint", + "format-check", + "test", + "cov", +] +test-lint = "lint-test" [[tool.hatch.envs.test.matrix]] python = ["37", "38", "39", "310", "311"] @@ -55,7 +77,7 @@ python = ["37", "38", "39", "310", "311"] branch = true parallel = true omit = [ - "coverage_rich/__about__.py", + "{{ python_package }}/__about__.py", ] [tool.coverage.report] @@ -64,3 +86,11 @@ exclude_lines = [ "if __name__ == .__main__.:", "if TYPE_CHECKING:", ] + +[tool.pytest.ini_options] +addopts = "-ra -q --rich" +asyncio_mode = "auto" +testpaths = ["tests"] + +[tool.coverage_rich] +fail-under=80 diff --git a/coverage_rich/__init__.py b/{{ package_name }}/tests/__init__.py similarity index 100% rename from coverage_rich/__init__.py rename to {{ package_name }}/tests/__init__.py diff --git a/{{ package_name }}/{{ _copier_conf.answers_file }}.jinja b/{{ package_name }}/{{ _copier_conf.answers_file }}.jinja new file mode 100644 index 0000000..1935679 --- /dev/null +++ b/{{ package_name }}/{{ _copier_conf.answers_file }}.jinja @@ -0,0 +1,2 @@ +# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY +{{ _copier_answers|to_nice_yaml }} diff --git a/coverage_rich/__about__.py b/{{ package_name }}/{{ python_package }}/__about__.py similarity index 80% rename from coverage_rich/__about__.py rename to {{ package_name }}/{{ python_package }}/__about__.py index dc32659..90da1db 100644 --- a/coverage_rich/__about__.py +++ b/{{ package_name }}/{{ python_package }}/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '0.0.1' +__version__ = "0.0.0.dev1" diff --git a/tests/__init__.py b/{{ package_name }}/{{ python_package }}/__init__.py similarity index 100% rename from tests/__init__.py rename to {{ package_name }}/{{ python_package }}/__init__.py diff --git a/coverage_rich/__main__.py b/{{ package_name }}/{{ python_package }}/__main__.py similarity index 67% rename from coverage_rich/__main__.py rename to {{ package_name }}/{{ python_package }}/__main__.py index e93030c..04b645e 100644 --- a/coverage_rich/__main__.py +++ b/{{ package_name }}/{{ python_package }}/__main__.py @@ -4,6 +4,6 @@ import sys if __name__ == '__main__': - from .cli import coverage_rich + from .cli import {{python_package}} - sys.exit(coverage_rich()) + sys.exit({{python_package}}()) diff --git a/{{ package_name }}/{{ python_package }}/cli/__init__.py b/{{ package_name }}/{{ python_package }}/cli/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/{{ package_name }}/{{ python_package }}/cli/app.py.jinja b/{{ package_name }}/{{ python_package }}/cli/app.py.jinja new file mode 100644 index 0000000..6812836 --- /dev/null +++ b/{{ package_name }}/{{ python_package }}/cli/app.py.jinja @@ -0,0 +1,52 @@ +import typer + +from {{ python_package }}.cli.common import verbose_callback +from {{ python_package }}.cli.config import config_app +from {{ python_package }}.cli.tui import tui_app + +app = typer.Typer( + name="{{ python_package }}", + help="A rich terminal report for coveragepy.", +) +app.add_typer(config_app) +app.add_typer(tui_app) + + +def version_callback(value: bool) -> None: + """Callback function to print the version of the {{ package_name }} package. + + Args: + value (bool): Boolean value to determine if the version should be printed. + + Raises: + typer.Exit: If the value is True, the version will be printed and the program will exit. + + Example: + version_callback(True) + """ + if value: + from {{ python_package }}.__about__ import __version__ + + typer.echo(f"{__version__}") + raise typer.Exit() + + +@app.callback() +def main( + version: bool = typer.Option( + None, + "--version", + callback=version_callback, + is_eager=True, + ), + verbose: bool = typer.Option( + False, + callback=verbose_callback, + help="show the log messages", + ), +) -> None: + return + + +if __name__ == "__main__": + typer.run(main) diff --git a/{{ package_name }}/{{ python_package }}/cli/common.py.jinja b/{{ package_name }}/{{ python_package }}/cli/common.py.jinja new file mode 100644 index 0000000..e470aad --- /dev/null +++ b/{{ package_name }}/{{ python_package }}/cli/common.py.jinja @@ -0,0 +1,6 @@ +from {{ python_package }}.console import console + + +def verbose_callback(value: bool) -> None: + if value: + console.quiet = False diff --git a/{{ package_name }}/{{ python_package }}/cli/config.py.jinja b/{{ package_name }}/{{ python_package }}/cli/config.py.jinja new file mode 100644 index 0000000..1def78f --- /dev/null +++ b/{{ package_name }}/{{ python_package }}/cli/config.py.jinja @@ -0,0 +1,29 @@ +from rich.console import Console +import typer + +from {{ python_package }}.cli.common import verbose_callback +from {{ python_package }}.config import config as configuration + +config_app = typer.Typer() + + +@config_app.callback() +def config( + verbose: bool = typer.Option( + False, + callback=verbose_callback, + help="show the log messages", + ), +): + "configuration cli" + + +@config_app.command() +def show( + verbose: bool = typer.Option( + False, + callback=verbose_callback, + help="show the log messages", + ), +): + Console().print(configuration) diff --git a/{{ package_name }}/{{ python_package }}/cli/tui.py.jinja b/{{ package_name }}/{{ python_package }}/cli/tui.py.jinja new file mode 100644 index 0000000..ef76d76 --- /dev/null +++ b/{{ package_name }}/{{ python_package }}/cli/tui.py.jinja @@ -0,0 +1,18 @@ +import typer + +from {{ python_package }}.cli.common import verbose_callback +from {{ python_package }}.tui.app import run_app + +tui_app = typer.Typer() + + +@tui_app.callback(invoke_without_command=True) +def i( + verbose: bool = typer.Option( + False, + callback=verbose_callback, + help="show the log messages", + ), +): + "interactive tui" + run_app() diff --git a/{{ package_name }}/{{ python_package }}/config.py.jinja b/{{ package_name }}/{{ python_package }}/config.py.jinja new file mode 100644 index 0000000..1b7bece --- /dev/null +++ b/{{ package_name }}/{{ python_package }}/config.py.jinja @@ -0,0 +1,3 @@ +from {{ python_package }}.standard_config import load + +config = load("{{ python_package }}") diff --git a/{{ package_name }}/{{ python_package }}/console.py b/{{ package_name }}/{{ python_package }}/console.py new file mode 100644 index 0000000..d160979 --- /dev/null +++ b/{{ package_name }}/{{ python_package }}/console.py @@ -0,0 +1,4 @@ +from rich.console import Console + +console = Console() +console.quiet = True diff --git a/{{ package_name }}/{{ python_package }}/standard_config.py b/{{ package_name }}/{{ python_package }}/standard_config.py new file mode 100644 index 0000000..0f99499 --- /dev/null +++ b/{{ package_name }}/{{ python_package }}/standard_config.py @@ -0,0 +1,239 @@ +"""Standard Config. +A module to load tooling config from a users project space. + +Inspired from frustrations that some tools have a tool.ini, .tool.ini, +setup.cfg, or pyproject.toml. Some allow for global configs, some don't. Some +properly follow the users home directory, others end up in a weird temp +directory. Windows home directory is only more confusing. Some will even +respect the users `$XDG_HOME` directory. + + +This file is for any project that can be configured in plain text such as `ini` +or `toml` and not requiring a .py file. Just name your tool and let users put +config where it makes sense to them, no need to figure out resolution order. + +## Usage: + +``` python +from standard_config import load + +# Retrieve any overrides from the user +overrides = {'setting': True} +config = load('my_tool', overrides) +``` + +## Resolution Order + +* First global file with a tool key +* First local file with a tool key +* Environment variables prefixed with `TOOL` +* Overrides + +### Tool Specific Ini files + +Ini file formats must include a `` key. + +``` ini +[my_tool] +setting = True +``` + +### pyproject.toml + +Toml files must include a `tool.` key + +``` toml +[tool.my_tool] +setting = True +``` + +### setup.cfg + +setup.cfg files must include a `tool:` key + +``` ini +[tool:my_tool] +setting = True +``` + + +### global files to consider + +* /tool.ini +* /.tool +* /.tool.ini +* /.config/tool.ini +* /.config/.tool +* /.config/.tool.ini + +### local files to consider + +* /tool.ini +* /.tool +* /.tool.ini +* /pyproject.toml +* /setup.cfg + +""" + +import os +from pathlib import Path +from typing import Dict, List, Union + +import anyconfig + +# path_spec_type = List[Dict[str, Union[Path, str, List[str\}\}\}\} +path_spec_type = List + + +def _get_global_path_specs(tool: str) -> path_spec_type: + """ + Generate a list of standard pathspecs for global config files. + + Args: + tool (str): name of the tool to configure + """ + try: + home = Path(os.environ["XDG_HOME"]) + except KeyError: + home = Path.home() + + return [ + {"path_specs": home / f"{tool}.ini", "ac_parser": "ini", "keys": [tool]}, + {"path_specs": home / f".{tool}", "ac_parser": "ini", "keys": [tool]}, + {"path_specs": home / f".{tool}.ini", "ac_parser": "ini", "keys": [tool]}, + { + "path_specs": home / ".config" / f"{tool}.ini", + "ac_parser": "ini", + "keys": [tool], + }, + { + "path_specs": home / ".config" / f".{tool}", + "ac_parser": "ini", + "keys": [tool], + }, + { + "path_specs": home / ".config" / f".{tool}.ini", + "ac_parser": "ini", + "keys": [tool], + }, + ] + + +def _get_local_path_specs(tool: str, project_home: Union[str, Path]) -> path_spec_type: + """ + Generate a list of standard pathspecs for local, project directory config files. + + Args: + tool (str): name of the tool to configure + """ + return [ + { + "path_specs": Path(project_home) / f"{tool}.ini", + "ac_parser": "ini", + "keys": [tool], + }, + { + "path_specs": Path(project_home) / f".{tool}", + "ac_parser": "ini", + "keys": [tool], + }, + { + "path_specs": Path(project_home) / f".{tool}.ini", + "ac_parser": "ini", + "keys": [tool], + }, + { + "path_specs": Path(project_home) / f"{tool}.yml", + "ac_parser": "yaml", + "keys": [tool], + }, + { + "path_specs": Path(project_home) / f".{tool}.yml", + "ac_parser": "yaml", + "keys": [tool], + }, + { + "path_specs": Path(project_home) / f"{tool}.toml", + "ac_parser": "toml", + "keys": [tool], + }, + { + "path_specs": Path(project_home) / f".{tool}.toml", + "ac_parser": "toml", + "keys": [tool], + }, + { + "path_specs": Path(project_home) / "pyproject.toml", + "ac_parser": "toml", + "keys": ["tool", tool], + }, + { + "path_specs": Path(project_home) / "setup.cfg", + "ac_parser": "ini", + "keys": [f"tool.{tool}"], + }, + ] + + +def _get_attrs(attrs: list, config: Dict) -> Dict: + """Get nested config data from a list of keys. + + specifically written for pyproject.toml which needs to get `tool` then `` + """ + for attr in attrs: + config = config[attr] + return config + + +def _load_files(config_path_specs: path_spec_type) -> Dict: + """Use anyconfig to load config files stopping at the first one that exists. + + config_path_specs (list): a list of pathspecs and keys to load + """ + for file in config_path_specs: + if file["path_specs"].exists(): + config = anyconfig.load(**file) + else: + # ignore missing files + continue + + try: + return _get_attrs(file["keys"], config) + except KeyError: + # ignore incorrect keys + continue + + return {} + + +def _load_env(tool: str) -> Dict: + """Load config from environment variables. + + Args: + tool (str): name of the tool to configure + """ + vars = [var for var in os.environ.keys() if var.startswith(tool.upper())] + return { + var.lower().strip(tool.lower()).strip("_").strip("-"): os.environ[var] + for var in vars + } + + +def load(tool: str, project_home: Union[Path, str] = ".", overrides: Dict = {}) -> Dict: + """Load tool config from standard config files. + + Resolution Order + + * First global file with a tool key + * First local file with a tool key + * Environment variables prefixed with `TOOL` + * Overrides + + Args: + tool (str): name of the tool to configure + """ + global_config = _load_files(_get_global_path_specs(tool)) + local_config = _load_files(_get_local_path_specs(tool, project_home)) + env_config = _load_env(tool) + return {**global_config, **local_config, **env_config, **overrides} diff --git a/{{ package_name }}/{{ python_package }}/tui/app.css b/{{ package_name }}/{{ python_package }}/tui/app.css new file mode 100644 index 0000000..7ed9fce --- /dev/null +++ b/{{ package_name }}/{{ python_package }}/tui/app.css @@ -0,0 +1,18 @@ +Screen { + align: center middle; + layers: main footer; +} + +Sidebar { + height: 100vh; + width: auto; + min-width: 20; + background: $secondary-background-darken-2; + dock: left; + margin-right: 1; + layer: main; +} + +Footer { + layer: footer; +} diff --git a/{{ package_name }}/{{ python_package }}/tui/app.py.jinja b/{{ package_name }}/{{ python_package }}/tui/app.py.jinja new file mode 100644 index 0000000..50ff47e --- /dev/null +++ b/{{ package_name }}/{{ python_package }}/tui/app.py.jinja @@ -0,0 +1,62 @@ +from pathlib import Path + +from textual.app import App, ComposeResult +from textual.containers import Container +from textual.css.query import NoMatches +from textual.widgets import Footer, Static + +from {{ python_package }}.config import config + +config["tui"] = {} +config["tui"]["bindings"] = {} + + +class Sidebar(Static): + def compose(self) -> ComposeResult: + yield Container( + Static("sidebar"), + id="sidebar", + ) + + +class Tui(App): + """A Textual app to manage requests.""" + + CSS_PATH = Path("__file__").parent / "app.css" + BINDINGS = [tuple(b.values()) for b in config["tui"]["bindings"]] + + def compose(self) -> ComposeResult: + """Create child widgets for the app.""" + yield Container(Static("hello world")) + yield Footer() + + def action_toggle_dark(self) -> None: + """An action to toggle dark mode.""" + self.dark = not self.dark + + def action_toggle_sidebar(self): + try: + self.query_one("PromptSidebar").remove() + except NoMatches: + self.mount(Sidebar()) + + +def run_app(): + import os + import sys + + from textual.features import parse_features + + dev = "--dev" in sys.argv + features = set(parse_features(os.environ.get("TEXTUAL", ""))) + if dev: + features.add("debug") + features.add("devtools") + + os.environ["TEXTUAL"] = ",".join(sorted(features)) + app = Tui() + app.run() + + +if __name__ == "__main__": + run_app()