Skip to content

Commit

Permalink
Merge branch 'releases/v.1.7.1' into pr/196
Browse files Browse the repository at this point in the history
  • Loading branch information
connorferster committed Jun 14, 2024
2 parents ed08616 + 949e114 commit 5b39a5d
Show file tree
Hide file tree
Showing 29 changed files with 973 additions and 270 deletions.
41 changes: 41 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Upload Python Package

on:
release:
types: [published]

permissions:
contents: read

jobs:
deploy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flit
flit install
- name: Build package
run: |
flit build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
36 changes: 36 additions & 0 deletions .github/workflows/python-pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: Python testing

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
build:
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
python-version: ["3.10", "3.11", "3.12"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flit
flit install
- name: Test black formatted
run: |
black handcalcs --check
- name: Test with pytest
run: |
pytest
55 changes: 52 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
<img src="https://img.shields.io/pypi/v/handcalcs">
<img src="https://img.shields.io/pypi/pyversions/handcalcs">
<img src="https://img.shields.io/github/license/connorferster/handcalcs">
<img src="https://img.shields.io/pypi/dm/handcalcs">
<img src="https://static.pepy.tech/badge/handcalcs">
</p>
<p align="center">
<img src="docs/images/handcalcs.jpg"><br>
Covert art by <a href = "https://www.instagram.com/joshuahoibergtattoos/">Joshua Hoiberg</a>
Covert art by <a href = "https://www.copperkettlegameworks.ca/">Joshua Hoiberg</a>
</p>

<h1 align = "center">handcalcs:<br>Python calculations in Jupyter,<br>as though you wrote them by hand.</h1>
Expand Down Expand Up @@ -85,7 +85,7 @@ import handcalcs.render
from math import sqrt, pi
```

Now, you can use the `%%tex` magic!
Now, you can also use the `%%tex` magic!

```python
%%tex
Expand Down Expand Up @@ -129,6 +129,55 @@ Used in this way, you can use `@handcalc()` to dynamically generate Latex code f

![Parameters](docs/images/decorator.png)

---

## Global config options (New in v1.6.0)

This is a major new release for handcalcs and introduces the global configuration feature. This allows users to have control over several options of how handcalcs works. The configuration options, with their default values, are as follow:

* `decimal_separator = "."`
* `latex_block_start = "\\["`
* `latex_block_end = "\\]"`
* `math_environment_start = "aligned"`
* `math_environment_end = "aligned"`
* `line_break = "\\\\[10pt]"`
* `use_scientific_notation = False`
* `display_precision = 3`
* `underscore_subscripts = True`
* `greek_exclusions = []`
* `param_columns = 3`
* `preferred_string_formatter = "L"`
* `custom_symbols = {}`

### Config API

```python
import handcalcs.render

handcalcs.set_option("display_precision", 4)
handcalcs.set_option("param_columns", 5)
handcalcs.set_option("line_break", "\\\\[20pt]")
handcalcs.set_option("greek_exclusions", ["psi"]) # etc...
```
These changes now affect all cells rendered in the current session. If you want to permanently update the `config.json` file with these changes (so handcalcs will always load up with these options), you can then call `handcalcs.save_config()` and the changes will be saved (and thus immediately available in the next session).

#### Custom Symbols (New in v1.7.0)

You can now add _custom symbols_ to your global config to handle ALL of the cases which handcalcs does not account for.

e.g.

```python
handcalcs.set_option("custom_symbols", {"V_dot": "\\dot{V}", "N_star": "N^{*}"})
```

Will now allow this kind of rendering:

![Custom symbols example showing the use of V_dot and N_star](docs/images/custom_symbols.png)

The docstring in the `handcalcs.set_option()` function demonstrates which options are available and what values they take.
---


## Override tags

Expand Down
Binary file added docs/images/custom_symbols.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion handcalcs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"""
Render arithmetic calucations in Jupyter as though they were written by hand.
"""
__version__ = "1.6.5" #
__version__ = "1.7.1" #
from .decorator import handcalc
from .global_config import set_option, save_config

Expand Down
3 changes: 2 additions & 1 deletion handcalcs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
"underscore_subscripts": true,
"greek_exclusions": [],
"param_columns": 3,
"preferred_string_formatter": "L"
"preferred_string_formatter": "L",
"custom_symbols": {}
}
2 changes: 1 addition & 1 deletion handcalcs/global_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def _load_global_config(config_file_name: str):
str_value = str_value.replace("\n", "\\n")
else:
str_value = str(value)
_OPTIONS.append(f"{key} -> {type(value)} (default = {str_value})")
_OPTIONS.append(f"{key}: {type(value)} (default = {str_value})")
# _OPTIONS = [f"{key} -> {type(value)} (default = {value})" for key, value in _config.items()]
_OPTIONS_TEXT = "Configuration can be set on the following options:\n\t" + "\n\t".join(
_OPTIONS
Expand Down
62 changes: 52 additions & 10 deletions handcalcs/handcalcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from handcalcs import global_config
from handcalcs.integrations import DimensionalityError


# Six basic line types
@dataclass
class CalcLine:
Expand Down Expand Up @@ -2051,6 +2052,7 @@ def swap_symbolic_calcs(
symbolic_expression = copy.copy(calculation)
functions_on_symbolic_expressions = [
insert_parentheses,
swap_custom_symbols,
swap_math_funcs,
swap_superscripts,
swap_chained_fracs,
Expand All @@ -2060,6 +2062,7 @@ def swap_symbolic_calcs(
swap_for_greek,
swap_prime_notation,
swap_long_var_strs,
swap_double_subscripts,
extend_subscripts,
swap_superscripts,
flatten_deque,
Expand Down Expand Up @@ -2095,11 +2098,12 @@ def swap_numeric_calcs(
swap_for_greek,
swap_prime_notation,
swap_superscripts,
swap_double_subscripts,
extend_subscripts,
flatten_deque,
]
for function in functions_on_numeric_expressions:
if function is swap_values or function is swap_math_funcs:
if function in (swap_values, swap_math_funcs):
numeric_expression = function(
numeric_expression, calc_results, **config_options
)
Expand Down Expand Up @@ -2146,6 +2150,28 @@ def swap_integrals(d: deque, calc_results: dict, **config_options) -> deque:
return d


def swap_custom_symbols(d: deque, **config_options) -> deque:
"""
Swaps the custom symbols from the 'config_options'.
"""
swapped_items = deque([])
for item in d:
if isinstance(item, deque):
new_item = swap_custom_symbols(item, **config_options)
swapped_items.append(new_item)
elif isinstance(item, str):
custom_symbols = config_options.get("custom_symbols", {})
new_item = item
for symbol, latex_symbol in custom_symbols.items():
if symbol in item:
new_item = item.replace(symbol, latex_symbol)
break
swapped_items.append(new_item)
else:
swapped_items.append(item)
return swapped_items


def swap_log_func(d: deque, calc_results: dict, **config_options) -> deque:
"""
Returns a new deque representing 'd' but with any log functions swapped
Expand Down Expand Up @@ -2341,6 +2367,23 @@ def list_to_deque(los: List[str]) -> deque:
return acc


def swap_double_subscripts(pycode_as_deque: deque, **config_options) -> deque:
"""
For variables or function names that contain a double subscript '__',
the double subscript will be replaced with LaTeX space: "\\ "
"""
swapped_deque = deque([])
for item in pycode_as_deque:
if isinstance(item, deque):
new_item = swap_double_subscripts(item)
elif isinstance(item, str) and "__" in item:
new_item = item.replace("__", "\\ ")
else:
new_item = item
swapped_deque.append(new_item)
return swapped_deque


def extend_subscripts(pycode_as_deque: deque, **config_options) -> deque:
"""
For variables named with a subscript, e.g. V_c, this function ensures that any
Expand All @@ -2355,7 +2398,7 @@ def extend_subscripts(pycode_as_deque: deque, **config_options) -> deque:
new_item = extend_subscripts(item) # recursion!
swapped_deque.append(new_item)
elif isinstance(item, str) and "_" in item and not "\\int" in item:
if "\\mathrm{" in item:
if "\\mathrm{" in item or "\\operatorname{" in item:
discount = 1
new_item = ""
for char in item:
Expand Down Expand Up @@ -2543,15 +2586,12 @@ def swap_math_funcs(
elif poss_func_name == "ceil" or poss_func_name == "floor":
new_item = swap_floor_ceil(item, poss_func_name, calc_results)
swapped_deque.append(new_item)
#
# elif possible_func and poss_func_name:
# elif possible_func:
elif possible_func:
ops = "\\operatorname"
new_func = f"{ops}{a}{poss_func_name}{b}"
item = swap_func_name(item, poss_func_name, new_func)
if possible_func:
item = insert_func_braces(item)
# if possible_func:
# item = insert_func_braces(item)
new_item = swap_math_funcs(item, calc_results)
swapped_deque.append(new_item)

Expand Down Expand Up @@ -2838,9 +2878,11 @@ def swap_for_greek(pycode_as_deque: deque, **config_options) -> deque:
elif "_" in str(item):
components = str(item).split("_")
swapped_components = [
dict_get(greek_chainmap, component)
if component not in greeks_to_exclude
else component
(
dict_get(greek_chainmap, component)
if component not in greeks_to_exclude
else component
)
for component in components
]
new_item = "_".join(swapped_components)
Expand Down
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ classifiers = ["License :: OSI Approved :: Apache Software License"]
dynamic = ["version", "description"]
dependencies = [
"more_itertools",
"nbconvert >= 6.0",
"innerscope",
"nbconvert >= 7.0.0",
"innerscope >= 0.7.0",
"pyparsing"
]

Expand All @@ -23,14 +23,14 @@ Source = "https://github.com/connorferster/handcalcs"
[project.optional-dependencies]

test = [
"pytest >= 6.0.0",
"pytest-cov >= 2.9.0",
"pytest >= 8.0.0",
"pytest-cov >= 4.1.0",
"coverage[toml] >= 5.5.0",
"pint >= 0.18",
"pint >= 0.23",
]

dev = [
"jupyterlab >= 3.0.0",
"jupyterlab >= 4.0.0",
"sympy",
"forallpeople >= 2.0",
"black"
Expand Down
Loading

0 comments on commit 5b39a5d

Please sign in to comment.