Skip to content

Commit

Permalink
Implement security best practices (#29)
Browse files Browse the repository at this point in the history
* Implement community guidelines (#27)
* Add Ruff linting
* Add scorecard report generation
* Implement security best practices
  • Loading branch information
makukha authored Aug 8, 2024
1 parent c5d0614 commit 03a690f
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tool.bumpversion]
current_version = "0.6.2"
current_version = "0.6.3"
allow_dirty = true

[[tool.bumpversion.files]]
Expand Down
16 changes: 15 additions & 1 deletion .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# Contributing

See [README.md](../README.md) file.
### Pull requests

To propose a feature or a bug fix, please create [pull request](https://github.com/makukha/caseutil/pulls).

Every pull request must ensure preserving 100% code coverage with tests.


### Coding style

This project uses [Black](https://black.readthedocs.io) coding style.


### Developing

For details on development environment setup, see [README.md](../README.md).
5 changes: 3 additions & 2 deletions .github/SUPPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

You can [create a new issue](https://github.com/makukha/caseutil/labels/question) with "question" label, for example to:

Ask a question or ask about a problem.
Suggest a new feature.
* Ask a question or ask about a problem.
* Submit bug report.
* Suggest a new feature.
38 changes: 38 additions & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Exclude a variety of commonly ignored directories.
exclude = [
".git",
".pdm-build",
".tox",
".venv",
"dist",
"tmp",
]
# Same as Black.
line-length = 88
indent-width = 4
# Assume Python 3.12
target-version = "py312"


[lint]

# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default.
select = ["E4", "E7", "E9", "F", "S"]
ignore = []
# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"


[format]

quote-style = "single"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
docstring-code-format = true
docstring-code-line-length = "dynamic"
6 changes: 3 additions & 3 deletions Brewfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# dev core
brew "keyring"
brew "pdm"
brew "pyenv"
brew "ruff"
brew "scorecard"
brew "tox"

# pyenv deps not covered by formula
brew "zlib"

# dev ux
cask "alacritty"
cask "font-jetbrains-mono-nerd-font"
70 changes: 47 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# caseutil ⇄ 🐍🐫🍢
> Case convert and verify for Python: snake_case, camelCase, kebab-case, etc.
>
[![license](https://img.shields.io/github/license/makukha/caseutil.svg)](https://github.com/makukha/caseutil/blob/main/LICENSE)
[![Tests](https://raw.githubusercontent.com/makukha/caseutil/0.6.2/docs/badge/tests.svg)](https://github.com/makukha/caseutil)
[![Coverage](https://raw.githubusercontent.com/makukha/caseutil/0.6.2/docs/badge/coverage.svg)](https://github.com/makukha/caseutil)
[![Tests](https://raw.githubusercontent.com/makukha/caseutil/0.6.3/docs/badge/tests.svg)](https://github.com/makukha/caseutil)
[![Coverage](https://raw.githubusercontent.com/makukha/caseutil/0.6.3/docs/badge/coverage.svg)](https://github.com/makukha/caseutil)
[](https://api.securityscorecards.dev/projects/github.com/anuraghazra/github-readme-stats/badge)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9342/badge)](https://www.bestpractices.dev/projects/9342) \
[![pypi](https://img.shields.io/pypi/v/caseutil.svg)](https://pypi.python.org/pypi/caseutil)
[![versions](https://img.shields.io/pypi/pyversions/caseutil.svg)](https://pypi.org/project/caseutil)

Case convert and verify for Python: snake_case, camelCase, kebab-case, and more.


## Features

Expand All @@ -18,7 +20,7 @@ Case convert and verify for Python: snake_case, camelCase, kebab-case, and more.
* 100% test coverage


## Supported Cases
### Supported cases

| Case | Example | Functions |
|-------------|------------------|--------------------------|
Expand All @@ -32,13 +34,15 @@ Case convert and verify for Python: snake_case, camelCase, kebab-case, and more.
| Title Space | My Variable Name | `is_title`, `to_title` |


## Installation
## Getting Started

### Installing

```bash
$ pip install caseutil
```

## Quick Start
### Use as a library

```doctest
>>> from caseutil import *
Expand All @@ -56,17 +60,23 @@ Convert to case:
'my_variable_name'
```

Use as command line tool, supports multiple values in argument or stdin:
### Use as a CLI command

Note the support of multiple values in argument or stdin:

```bash
$ caseutil -c const "hi there"
HI_THERE

$ echo "hi_there\nsee you" | python -m caseutil -c camel
hiThere
seeYou
```


## Universal Functions
## Advanced

### Universal functions

Use functions `is_case()` and `to_case()` to deal with arbitrary case:
```doctest
Expand All @@ -76,6 +86,8 @@ True
'MY_VARIABLE_NAME'
```

### Case enum

All supported cases are gathered in `Case` enum:
```python
class Case(StrEnum):
Expand All @@ -89,8 +101,7 @@ class Case(StrEnum):
UPPER = 'upper'
```


## Tokenization
### Tokenization

Word separators are non-word characters including underscore, and places where text case is changed from lower to upper. Digits are not treated as separators. For more details, see this example and unit tests.

Expand All @@ -99,7 +110,7 @@ Word separators are non-word characters including underscore, and places where t
['some', 'really', 'ME', 'Ssy', 'text', 'wit4', 'Digits', '3Very', 'Wh3re']
```

## Custom Separators
### Custom Separators

For custom separators, use `words()` function:
```doctest
Expand All @@ -109,15 +120,16 @@ For custom separators, use `words()` function:
'my.Variable.Name'
```


## Unicode
### Unicode support

Only ASCII names are supported. Unicode support is planned.


## Developer Notes
## Developing

### Development environment

### OS X
#### OS X

This project requires [Homebrew](https://brew.sh). Other tools like [PDM](https://pdm-project.org), [Tox](https://tox.wiki), and even [Alacritty](https://alacritty.org), will be installed automatically.

Expand All @@ -128,17 +140,29 @@ brew bundle
task init install
```

### Operations
### Testing

| Command | Description |
|----------------|-------------------------------|
| `task init` | Initialize system environment |
| `task install` | Install Python environment |
| `task test` | Run tests |
```bash
task test
```

### Contributing

See [Contributing](.github/CONTRIBUTING.md) guidelines.

### Plans

### Roadmap

* Add more test, explore edge cases
* Add Unicode support (write tests)
* Add more cases


## Authors

* Mchael Makukha — initial author.


## License

This project is licensed under the terms of the [MIT license](LICENSE).
14 changes: 14 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
version: '3'

vars:
GITHUB_REPO: makukha/caseutil
GET_PYTHON_VERSIONS: tox --listenvs | sed -e 's/^py//' | xargs echo

tasks:
Expand Down Expand Up @@ -28,6 +29,11 @@ tasks:
cmds:
- pdm install --check --dev

lint:
desc: Run linters and code formatters.
cmds:
- ruff check

gen:test_readme:
internal: true
sources: [README.md]
Expand Down Expand Up @@ -71,3 +77,11 @@ tasks:
for: {var: PYTHON_VERSIONS}
silent: true

docs:scorecard:
desc: Update security scorecard
vars:
GITHUB_TOKEN: {sh: keyring get token.github.caseutil scorecard}
env:
GITHUB_TOKEN: '{{.GITHUB_TOKEN}}'
cmds:
- scorecard --repo={{.GITHUB_REPO}}
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ classifiers = [ # see https://pypi.org/classifiers/
"Typing :: Typed",
]
requires-python = ">=2.7,!=3.0,!=3.1,!=3.2,!=3.3,!=3.4"
dependencies = []

[project.scripts]
caseutil = "caseutil:main"
Expand Down
38 changes: 19 additions & 19 deletions src/caseutil.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
Case convert and verify for Python: snake_case, camelCase, kebab-case, and more.
"""
__version__ = '0.6.2'
__version__ = '0.6.3'

from argparse import ArgumentParser
from io import TextIOBase
Expand Down Expand Up @@ -147,27 +147,27 @@ def to_upper(text: str) -> str:
# universal functions

def is_case(case: Case | str, text: str) -> bool:
if case == Case.CAMEL: return is_camel(text)
elif case == Case.CONST: return is_const(text)
elif case == Case.KEBAB: return is_kebab(text)
elif case == Case.LOWER: return is_lower(text)
elif case == Case.PASCAL: return is_pascal(text)
elif case == Case.SNAKE: return is_snake(text)
elif case == Case.TITLE: return is_title(text)
elif case == Case.UPPER: return is_upper(text)
else: raise ValueError(f'Unsupported case: {case}')
if case == Case.CAMEL: return is_camel(text) # noqa: E701
elif case == Case.CONST: return is_const(text) # noqa: E701
elif case == Case.KEBAB: return is_kebab(text) # noqa: E701
elif case == Case.LOWER: return is_lower(text) # noqa: E701
elif case == Case.PASCAL: return is_pascal(text) # noqa: E701
elif case == Case.SNAKE: return is_snake(text) # noqa: E701
elif case == Case.TITLE: return is_title(text) # noqa: E701
elif case == Case.UPPER: return is_upper(text) # noqa: E701
else: raise ValueError(f'Unsupported case: {case}') # noqa: E701


def to_case(case: Case | str, text: str) -> str:
if case == Case.CAMEL: return to_camel(text)
elif case == Case.CONST: return to_const(text)
elif case == Case.KEBAB: return to_kebab(text)
elif case == Case.LOWER: return to_lower(text)
elif case == Case.PASCAL: return to_pascal(text)
elif case == Case.SNAKE: return to_snake(text)
elif case == Case.TITLE: return to_title(text)
elif case == Case.UPPER: return to_upper(text)
else: raise ValueError(f'Unsupported case: {case}')
if case == Case.CAMEL: return to_camel(text) # noqa: E701
elif case == Case.CONST: return to_const(text) # noqa: E701
elif case == Case.KEBAB: return to_kebab(text) # noqa: E701
elif case == Case.LOWER: return to_lower(text) # noqa: E701
elif case == Case.PASCAL: return to_pascal(text) # noqa: E701
elif case == Case.SNAKE: return to_snake(text) # noqa: E701
elif case == Case.TITLE: return to_title(text) # noqa: E701
elif case == Case.UPPER: return to_upper(text) # noqa: E701
else: raise ValueError(f'Unsupported case: {case}') # noqa: E701


# cli
Expand Down

0 comments on commit 03a690f

Please sign in to comment.