Skip to content

Commit 18c126e

Browse files
Merge pull request #8 from Ottermatics/cicd
refactor for pypi
2 parents b326cff + 87662e3 commit 18c126e

20 files changed

+129
-95
lines changed

.github/workflows/build.yml

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,26 @@ on:
1919
workflow_dispatch:
2020
workflow_call:
2121
jobs:
22-
test:
22+
format:
2323
runs-on: ubuntu-latest
24-
strategy:
25-
fail-fast: false
26-
matrix:
27-
python-version: [ "3.9", "3.10", "3.11" ]
28-
24+
if: github.event_name == 'pull_request'
25+
permissions:
26+
contents: write
2927
steps:
3028
- uses: actions/checkout@v4
3129
with:
3230
token: ${{ secrets.GITHUB_TOKEN }}
33-
31+
ref: ${{ github.head_ref || github.ref }}
32+
3433
- name: Install Python
3534
uses: actions/setup-python@v4
3635
with:
37-
python-version: ${{ matrix.python-version }}
36+
python-version: "3.11"
3837

39-
- name: Install dependencies
38+
- name: Install Black
4039
run: |
4140
python -m pip install --upgrade pip
42-
pip install flake8 pytest black
43-
pip install -e .[all]
44-
45-
- name: Display Python Version
46-
run: python -c "import sys; print(sys.version)"
41+
pip install black
4742
4843
- name: Check for existing release
4944
if: github.event_name == 'pull_request'
@@ -63,23 +58,49 @@ jobs:
6358
else
6459
echo "Version v$VERSION is available"
6560
fi
66-
env:
67-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6861
6962
- name: Auto-format with Black
70-
if: github.event_name == 'pull_request'
7163
run: |
7264
black ./engforge
7365
if ! git diff --quiet; then
7466
git config --local user.email "[email protected]"
7567
git config --local user.name "GitHub Action"
7668
git add -A
7769
git commit -m "Auto-format code with Black [skip ci]" || exit 0
78-
git push
70+
git push origin HEAD:${{ github.head_ref }}
7971
fi
72+
env:
73+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
74+
75+
test:
76+
runs-on: ubuntu-latest
77+
needs: [format]
78+
if: always() && (needs.format.result == 'success' || needs.format.result == 'skipped')
79+
strategy:
80+
fail-fast: false
81+
matrix:
82+
python-version: [ "3.9", "3.10", "3.11" ]
83+
84+
steps:
85+
- uses: actions/checkout@v4
86+
with:
87+
token: ${{ secrets.GITHUB_TOKEN }}
88+
ref: ${{ github.head_ref || github.ref }}
89+
90+
- name: Install Python
91+
uses: actions/setup-python@v4
92+
with:
93+
python-version: ${{ matrix.python-version }}
8094

81-
- name: Run tests
82-
run: python -m unittest discover -s engforge/test -p "test_*.py" -v
95+
- name: Install dependencies
96+
run: |
97+
python -m pip install --upgrade pip
98+
pip install flake8 pytest black
99+
pip install -e .[all]
83100
84-
- name: Verify Black formatting
85-
run: black --check --verbose ./engforge
101+
- name: Check Python & Run Tests
102+
run: |
103+
python -c "import sys; print(sys.version)"
104+
python -m pip list | grep PyNiteFEA || echo "pynite-not-found"
105+
python -m pip list | grep coolprop || echo "coolprop-not-found"
106+
python -m unittest discover -s engforge/test -p "test_*.py" -v

engforge/_testing_components.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ class Comp2(Norm, CostModel):
760760
comp1 = Slot.define(Comp1, none_ok=True, default_ok=False)
761761

762762

763-
quarterly = lambda inst, term: True if (term + 1) % 3 == 0 else False
763+
quarterly = lambda inst, term, econ: True if (term + 1) % 3 == 0 else False
764764

765765

766766
@forge

engforge/attr_plotting.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
"""This module defines Plot and Trace methods that allow the plotting of Statistical & Transient relationships of data in each system
2-
"""
1+
"""This module defines Plot and Trace methods that allow the plotting of Statistical & Transient relationships of data in each system"""
32

43
import attrs
54
import uuid

engforge/attributes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Defines a customizeable attrs attribute that is handled in configuration,
22
3-
on init an instance of `Instance` type for any ATTR_BASE subclass is created """
3+
on init an instance of `Instance` type for any ATTR_BASE subclass is created"""
44

55
import attrs, attr, uuid
66
from engforge.logging import LoggingMixin, log

engforge/component_collections.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"""define a collection of components that will propigate to its parents dataframe
22
3-
When `wide` is set each component's references are reported to the system's table, otherwise only one component's references are reported, however the system will iterate over the components by calling `system.iterable_components`
3+
When `wide` is set each component's references are reported to the system's table, otherwise only one component's references are reported, however the system will iterate over the components by calling `system.iterable_components`
44
55
Define a Iterable Component slot in a system by calling `Slot.define_iterable(...,wide=True/False)`
66
77
CostModel isonly supported in wide mode at this time.
88
9-
Types:
9+
Types:
1010
1. ComponentList, ordered by index
1111
2. ComponentDict, ordered by key
1212
3. ComponentGraph, ?#TODO:

engforge/configuration.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,11 +331,12 @@ def signals_slots_handler(
331331
f"{cls.__name__} overriding inherited attr: {o.name} as a system property overriding it"
332332
)
333333
elif o.inherited and k in cls_dict:
334-
log.debug(
334+
log.warning(
335335
f"{cls.__name__} overriding inherited attr: {o.name} as {cls_dict[k]} in cls"
336336
)
337337
# FIXME: should we deepcopy?
338-
cls.__anony_store[k] = sscb = lambda: copy.copy(cls_dict[k])
338+
val = copy.copy(cls_dict[k])
339+
cls.__anony_store[k] = sscb = lambda: val
339340
out.append(o.evolve(default=attrs.Factory(sscb)))
340341
else:
341342
log.msg(f"{cls.__name__} adding attr: {o.name}")

engforge/datastores/__init__.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import importlib.util
55
from pathlib import Path
66

7+
78
def get_project_root():
89
"""Find the project root containing pyproject.toml"""
910
current = Path(__file__).parent
@@ -13,71 +14,84 @@ def get_project_root():
1314
current = current.parent
1415
return None
1516

17+
1618
def install_optional_dependencies(group_name="database"):
1719
"""Install optional dependencies for a specific group"""
1820
project_root = get_project_root()
1921
if not project_root:
2022
print("Could not find pyproject.toml. Manual installation required:")
2123
print(f"pip install engforge[{group_name}]")
2224
return False
23-
25+
2426
try:
2527
# Try to import tomllib (Python 3.11+) or tomli (fallback)
2628
try:
2729
import tomllib
2830
except ImportError:
2931
import tomli as tomllib
30-
32+
3133
# Read pyproject.toml
3234
with open(project_root / "pyproject.toml", "rb") as f:
3335
config = tomllib.load(f)
34-
36+
3537
optional_deps = config.get("project", {}).get("optional-dependencies", {})
3638
if group_name not in optional_deps:
3739
print(f"No optional dependency group '{group_name}' found")
3840
return False
39-
41+
4042
# Install the optional dependencies
4143
package_name = config.get("project", {}).get("name", "engforge")
4244
install_spec = f"{package_name}[{group_name}]"
43-
45+
4446
print(f"Installing {install_spec}...")
45-
result = subprocess.run([
46-
sys.executable, "-m", "pip", "install", install_spec
47-
], capture_output=True, text=True)
48-
47+
result = subprocess.run(
48+
[sys.executable, "-m", "pip", "install", install_spec],
49+
capture_output=True,
50+
text=True,
51+
)
52+
4953
if result.returncode == 0:
5054
print(f"✅ Successfully installed {install_spec}")
5155
return True
5256
else:
5357
print(f"❌ Failed to install {install_spec}")
5458
print(f"Error: {result.stderr}")
5559
return False
56-
60+
5761
except Exception as e:
5862
print(f"Error during auto-installation: {e}")
5963
print(f"Please install manually: pip install engforge[{group_name}]")
6064
return False
6165

66+
6267
def check_and_install_datastores():
6368
"""Check if datastores dependencies are available, auto-install if needed"""
6469
try:
6570
import engforge.datastores.data
71+
6672
return True
6773
except ImportError as e:
6874
print(f"Datastores dependencies not available: {e}")
6975
print("")
70-
76+
7177
# Check if we're in development mode (editable install) and interactive
7278
project_root = get_project_root()
73-
is_interactive = hasattr(sys, 'ps1') or sys.stdout.isatty()
74-
75-
if project_root and (project_root / "pyproject.toml").exists() and is_interactive:
79+
is_interactive = hasattr(sys, "ps1") or sys.stdout.isatty()
80+
81+
if (
82+
project_root
83+
and (project_root / "pyproject.toml").exists()
84+
and is_interactive
85+
):
7686
try:
77-
answer = input("Auto-install database dependencies? (y/N): ").strip().lower()
78-
if answer in ['y', 'yes']:
87+
answer = (
88+
input("Auto-install database dependencies? (y/N): ").strip().lower()
89+
)
90+
if answer in ["y", "yes"]:
7991
if install_optional_dependencies("database"):
80-
print("Please restart your Python session to use the newly installed dependencies.")
92+
print(
93+
"Please restart your Python session to use the newly installed dependencies."
94+
)
8195
return False
8296
else:
8397
print("Auto-installation failed. Install manually with:")
@@ -96,6 +110,7 @@ def check_and_install_datastores():
96110
print("pip install engforge[database]")
97111
return False
98112

113+
99114
# Auto-check and install on import
100115
if not check_and_install_datastores():
101116
pass # Dependencies not available, but user has been informed

engforge/dynamics.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
99
#TODO: The top level system will collect the underlying dynamical systems and combine them to an index and overall state space model. This will allow for the creation of a system of systems, and the ability to create a system of systems with a single state space model.
1010
11-
#TODO: integration is done by the solver, where DynamicSystems have individual solver control, solver control is set for a smart default scipy
11+
#TODO: integration is done by the solver, where DynamicSystems have individual solver control, solver control is set for a smart default scipy
1212
"""
1313

1414
from engforge.configuration import Configuration, forge
@@ -29,7 +29,6 @@
2929
from collections import OrderedDict
3030
import numpy as np
3131
import pandas
32-
import expiringdict
3332
import attr, attrs
3433

3534

engforge/eng/costs.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
55
CostModel's can have cost_property's which detail how and when a cost should be applied & grouped. By default each CostModel has a `cost_per_item` which is reflected in `item_cost` cost_property set on the `initial` term as a `unit` category. Multiple categories of cost are also able to be set on cost_properties as follows
66
7-
Cost Models can represent multiple instances of a component, and can be set to have a `num_items` multiplier to account for multiple instances of a component. CostModels can have a `term_length` which will apply costs over the term, using the `cost_property.mode` to determine at which terms a cost should be applied.
7+
Cost Models can represent multiple instances of a component, and can be set to have a `num_items` multiplier to account for multiple instances of a component. CostModels can have a `term_length` which will apply costs over the term, using the `cost_property.mode` to determine at which terms a cost should be applied.
88
99
```
1010
@forge
1111
class Widget(Component,CostModel):
12-
12+
1313
#use num_items as a multiplier for costs, `cost_properties` can have their own custom num_items value.
14-
num_items:float = 100
14+
num_items:float = 100
1515
1616
@cost_property(mode='initial',category='capex,manufacturing',num_items=1)
1717
def cost_of_XYZ(self) -> float:

engforge/eng/geometry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""These exist as in interface to sectionproperties from PyNite"""
1+
"""These exist as in interface to sectionproperties from Pynite"""
22

33
from engforge.configuration import Configuration, forge, LoggingMixin
44
from engforge.properties import (

0 commit comments

Comments
 (0)