Public/New-PythonProject.ps1
|
function New-PythonProject { <# .SYNOPSIS Creates a runnable Python package project. .DESCRIPTION Creates a pyproject.toml-based src-layout package with a README, gitignore, package initializer, and pytest import test. .PARAMETER Name Project directory and distribution name. .PARAMETER Path Parent directory in which the project is created. .PARAMETER PackageName Import package name. Defaults to a normalized form of Name. .PARAMETER Description Project description used in pyproject.toml and README.md. .PARAMETER Force Allows an existing project directory and overwrites generated files. .EXAMPLE mkpyproj sample-app -PackageName sample_app #> [CmdletBinding(SupportsShouldProcess = $true)] [Alias('mkpyproj')] [OutputType([System.IO.DirectoryInfo])] param( [Parameter(Mandatory = $true, Position = 0)] [ValidatePattern('^[A-Za-z0-9][A-Za-z0-9._-]*$')] [string]$Name, [Parameter()] [string]$Path = (Get-Location).Path, [Parameter()] [string]$PackageName, [Parameter()] [string]$Description = 'Python project generated by DevXToolkit.', [switch]$Force ) if ([string]::IsNullOrWhiteSpace($PackageName)) { $PackageName = ($Name -replace '[-.]', '_').ToLowerInvariant() } $PackageName = ConvertTo-DtPythonIdentifier -Name $PackageName -ParameterName 'PackageName' $projectRoot = Resolve-DtContainedPath -BasePath $Path -ChildName $Name if ((Test-Path -LiteralPath $projectRoot) -and -not $Force) { throw "Project already exists. Use -Force to update generated files: $projectRoot" } if (-not $PSCmdlet.ShouldProcess($projectRoot, 'Create Python project')) { return } $packageRoot = Join-Path -Path $projectRoot -ChildPath "src/$PackageName" $testsRoot = Join-Path -Path $projectRoot -ChildPath 'tests' New-DtDirectory -Path $projectRoot -Confirm:$false | Out-Null New-DtDirectory -Path $packageRoot -Confirm:$false | Out-Null New-DtDirectory -Path $testsRoot -Confirm:$false | Out-Null $safeTitle = ConvertTo-DtSafeMarkdownText -Text $Name $safeDescription = ConvertTo-DtSafeMarkdownText -Text $Description $tomlName = ConvertTo-DtTomlString -Text $Name $tomlDescription = ConvertTo-DtTomlString -Text $Description $pyproject = @" [build-system] requires = ["setuptools>=68"] build-backend = "setuptools.build_meta" [project] name = "$tomlName" version = "0.1.0" description = "$tomlDescription" requires-python = ">=3.9" [tool.setuptools.packages.find] where = ["src"] [tool.pytest.ini_options] pythonpath = ["src"] testpaths = ["tests"] "@ $readme = @" # $safeTitle $safeDescription ## Development ``````powershell python -m pip install -e . python -m pytest `````` "@ $gitignore = @" __pycache__/ *.py[cod] .pytest_cache/ .venv/ build/ dist/ *.egg-info/ "@ $testContent = @" def test_package_imports(): import $PackageName assert $PackageName is not None "@ Set-DtFileContent -Path (Join-Path $projectRoot 'pyproject.toml') -Content $pyproject -Force:$Force -Confirm:$false | Out-Null Set-DtFileContent -Path (Join-Path $projectRoot 'README.md') -Content $readme -Force:$Force -Confirm:$false | Out-Null Set-DtFileContent -Path (Join-Path $projectRoot '.gitignore') -Content $gitignore -Force:$Force -Confirm:$false | Out-Null Set-DtFileContent -Path (Join-Path $packageRoot '__init__.py') -Content ('"""' + $PackageName + ' package."""') -Force:$Force -Confirm:$false | Out-Null Set-DtFileContent -Path (Join-Path $testsRoot 'test_import.py') -Content $testContent -Force:$Force -Confirm:$false | Out-Null Get-Item -LiteralPath $projectRoot } |