Skip to content

Commit 1d4b74a

Browse files
committed
Convert to proper PyPI package
- Switch from Poetry to hatchling - Add CLI entry point (replacetext command) - Add --config, --dry-run options - Add GitHub Actions CI + publish workflows - Update README for pip install - Fix linting issues
1 parent 0893e37 commit 1d4b74a

8 files changed

Lines changed: 294 additions & 169 deletions

File tree

.github/workflows/ci.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: ["3.9", "3.10", "3.11", "3.12"]
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Set up Python ${{ matrix.python-version }}
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
24+
- name: Install dependencies
25+
run: |
26+
python -m pip install --upgrade pip
27+
pip install -e ".[dev]"
28+
29+
- name: Lint with Ruff
30+
run: ruff check .
31+
32+
- name: Check formatting with Ruff
33+
run: ruff format --check .
34+
35+
- name: Run tests
36+
run: pytest

.github/workflows/publish.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: "Version to publish (must match pyproject.toml)"
8+
required: true
9+
type: string
10+
11+
jobs:
12+
publish:
13+
runs-on: ubuntu-latest
14+
environment: pypi
15+
permissions:
16+
contents: read
17+
id-token: write
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Set up Python
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: "3.12"
26+
27+
- name: Install build dependencies
28+
run: |
29+
python -m pip install --upgrade pip
30+
pip install build
31+
32+
- name: Verify version matches
33+
run: |
34+
VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
35+
if [ "$VERSION" != "${{ inputs.version }}" ]; then
36+
echo "Error: Input version (${{ inputs.version }}) does not match pyproject.toml version ($VERSION)"
37+
exit 1
38+
fi
39+
echo "Version verified: $VERSION"
40+
41+
- name: Build package
42+
run: python -m build
43+
44+
- name: Publish to PyPI
45+
uses: pypa/gh-action-pypi-publish@release/v1

README.md

Lines changed: 61 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,84 @@
1-
# ReplaceText
1+
# replacetext
22

3-
This project replaces text in files based on a dictionary, given user input to specify which direction (keys-to-values or values-to-keys).
3+
**Bulk text replacement in files using dictionary mappings.**
44

5-
## Features
5+
[![PyPI version](https://badge.fury.io/py/replacetext.svg)](https://badge.fury.io/py/replacetext)
6+
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
67

7-
- Replace text in files based on dictionaries defined in a configuration file.
8-
- Allows user to specify the direction of replacement (keys-to-values or values-to-keys).
9-
- Allows user to specify which file extensions, file prefixes, or directories to ignore.
10-
- Automatically uses the only dictionary if only one is defined in the configuration file.
11-
12-
## Requirements
13-
14-
- Python 3.8 or higher
15-
- Poetry package manager
8+
Replace text across multiple files using find/replace dictionaries. Supports bidirectional replacement (keys-to-values or values-to-keys).
169

1710
## Installation
1811

19-
1. **Install Poetry** (if not already installed):
20-
21-
```sh
22-
curl -sSL https://install.python-poetry.org | python3 -
23-
```
24-
25-
2. **Clone the repository and navigate to the project directory**:
26-
27-
```sh
28-
git clone https://github.com/cainky/ReplaceText.git
29-
cd ReplaceText
30-
```
31-
32-
3. **Install dependencies**:
33-
34-
```sh
35-
poetry install
36-
```
12+
```bash
13+
pip install replacetext
14+
```
3715

38-
## Configuration
16+
## Quick Start
3917

40-
1. **Rename the example configuration file**:
18+
1. Create a config file (`config.json`):
4119

42-
```sh
43-
mv example_config.json config.json
44-
```
20+
```json
21+
{
22+
"dictionaries": {
23+
"example": {
24+
"old_text": "new_text",
25+
"foo": "bar"
26+
}
27+
},
28+
"ignore_extensions": [".exe", ".bin"],
29+
"ignore_directories": ["node_modules", ".git"],
30+
"ignore_file_prefixes": [".", "_"]
31+
}
32+
```
4533

46-
2. **Edit `config.json` to define your dictionaries**. Here is an example
34+
2. Run:
4735

48-
```json
49-
{
50-
"dictionaries": {
51-
"example1": {
52-
"key1": "value1",
53-
"key2": "value2",
54-
"key3": "value3"
55-
},
56-
"example2": {
57-
"hello": "world",
58-
"foo": "bar",
59-
"python": "rocks"
60-
}
61-
},
62-
"ignore_extensions": [".exe", ".dll", ".bin"],
63-
"ignore_directories": ["node_modules", "venv", ".git"],
64-
"ignore_file_prefixes": [".", "_"]
65-
}
66-
```
36+
```bash
37+
replacetext -f ./my_folder -d 1
38+
```
6739

6840
## Usage
6941

70-
Run the script using Poetry:
71-
72-
```sh
73-
poetry run python replace_text/replace_text.py
74-
```
42+
```bash
43+
# Interactive mode
44+
replacetext
7545

76-
The script will prompt you for the following inputs:
46+
# With options
47+
replacetext --folder ./src --direction 1 --config my_config.json
7748

78-
Direction of replacement:
49+
# Dry run (preview changes)
50+
replacetext -f ./src -d 1 --dry-run
7951

80-
- Enter '1' for keys-to-values
81-
- Enter '2' for values-to-keys
52+
# Reverse direction (values-to-keys)
53+
replacetext -f ./src -d 2
54+
```
8255

83-
Folder path:
56+
## Options
8457

85-
- Enter the path to the folder containing the files to be processed.
58+
| Option | Short | Description |
59+
|--------|-------|-------------|
60+
| `--folder` | `-f` | Folder to process |
61+
| `--direction` | `-d` | 1 = keys-to-values, 2 = values-to-keys |
62+
| `--config` | `-c` | Path to config file (default: config.json) |
63+
| `--dict-name` | `-n` | Dictionary name (auto-selects if only one) |
64+
| `--dry-run` | | Preview changes without modifying files |
8665

87-
Dictionary name:
66+
## Config Format
8867

89-
- Enter the name of the dictionary to use from config.json.
90-
The script will process all files in the specified folder, replacing text based on the selected dictionary and direction.
68+
```json
69+
{
70+
"dictionaries": {
71+
"my_replacements": {
72+
"find_this": "replace_with_this",
73+
"old": "new"
74+
}
75+
},
76+
"ignore_extensions": [".exe", ".dll"],
77+
"ignore_directories": ["node_modules", "venv"],
78+
"ignore_file_prefixes": [".", "_"]
79+
}
80+
```
9181

9282
## License
93-
ReplaceText is distributed under the [GNU General Public License, Version 3](./LICENSE), allowing for free software distribution and modification while ensuring that all copies and modified versions remain free.
83+
84+
GPL v3

poetry.lock

Lines changed: 0 additions & 34 deletions
This file was deleted.

pyproject.toml

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,60 @@
1-
[tool.poetry]
2-
name = "replace_text"
1+
[build-system]
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "replacetext"
37
version = "0.1.0"
4-
description = "Replaces text based on a dictionary, given user input to specify which direction (keys-to-values or values-to-keys)"
5-
authors = ["Kyle Cain <kylecain.me@gmail.com>"]
8+
description = "Bulk text replacement in files using dictionary mappings"
69
readme = "README.md"
10+
license = "GPL-3.0-or-later"
11+
authors = [
12+
{ name = "Kyle Cain", email = "kyle@kylecain.me" }
13+
]
14+
keywords = ["text", "replace", "bulk", "dictionary", "find-replace", "cli"]
15+
classifiers = [
16+
"Development Status :: 4 - Beta",
17+
"Environment :: Console",
18+
"Intended Audience :: Developers",
19+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
20+
"Operating System :: OS Independent",
21+
"Programming Language :: Python :: 3",
22+
"Programming Language :: Python :: 3.9",
23+
"Programming Language :: Python :: 3.10",
24+
"Programming Language :: Python :: 3.11",
25+
"Programming Language :: Python :: 3.12",
26+
"Topic :: Text Processing",
27+
"Topic :: Utilities",
28+
]
29+
requires-python = ">=3.9"
30+
dependencies = [
31+
"click>=8.0.0",
32+
]
733

8-
[tool.poetry.dependencies]
9-
python = "^3.10"
10-
click = "^8.3.1"
34+
[project.optional-dependencies]
35+
dev = [
36+
"pytest>=7.0.0",
37+
"pytest-cov>=4.0.0",
38+
"ruff>=0.1.0",
39+
]
1140

41+
[project.scripts]
42+
replacetext = "replace_text.replace_text:replace_text"
1243

13-
[build-system]
14-
requires = ["poetry-core"]
15-
build-backend = "poetry.core.masonry.api"
44+
[project.urls]
45+
Homepage = "https://github.com/cainky/ReplaceText"
46+
Repository = "https://github.com/cainky/ReplaceText"
47+
Issues = "https://github.com/cainky/ReplaceText/issues"
48+
49+
[tool.hatch.build.targets.wheel]
50+
packages = ["replace_text"]
51+
52+
[tool.ruff]
53+
line-length = 100
54+
target-version = "py39"
55+
56+
[tool.ruff.lint]
57+
select = ["E", "F", "I", "N", "W", "UP"]
58+
59+
[tool.pytest.ini_options]
60+
testpaths = ["replace_text/tests"]

replace_text/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""replacetext - Bulk text replacement in files using dictionary mappings."""
2+
3+
__version__ = "0.1.0"

0 commit comments

Comments
 (0)