From 66e1bd6638be3994d7cc8e5632029874968db444 Mon Sep 17 00:00:00 2001 From: Ryan Wellborn Date: Mon, 5 May 2025 21:23:28 -0600 Subject: [PATCH 1/2] Fixes #21 --- planar_magnetics/config.py | 14 +++++ planar_magnetics/cores/cores.py | 5 +- planar_magnetics/geometry.py | 3 +- planar_magnetics/transformers/transformers.py | 3 +- tests/test_config.py | 37 ++++++++++++ tests/test_geometry.py | 58 ++++++++++++++++++- 6 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 planar_magnetics/config.py create mode 100644 tests/test_config.py diff --git a/planar_magnetics/config.py b/planar_magnetics/config.py new file mode 100644 index 0000000..aa9428f --- /dev/null +++ b/planar_magnetics/config.py @@ -0,0 +1,14 @@ +import os + + +# Default path to FreeCAD binaries +DEFAULT_FREECAD_PATH = "C:/Program Files/FreeCAD 0.19/bin" + + +# Function to get FreeCAD path with environment variable override +def get_freecad_path(): + """ + Get the FreeCAD path from environment variable FREECAD_PATH if available, + otherwise use the default path. + """ + return os.getenv("FREECAD_PATH", DEFAULT_FREECAD_PATH) diff --git a/planar_magnetics/cores/cores.py b/planar_magnetics/cores/cores.py index 25bda35..7702012 100644 --- a/planar_magnetics/cores/cores.py +++ b/planar_magnetics/cores/cores.py @@ -8,6 +8,7 @@ TWO_PI, PI_OVER_TWO, ) +from planar_magnetics.config import get_freecad_path def calculate_core_extension(area: float, radius: float, opening_width: float) -> float: @@ -132,7 +133,7 @@ def get_coreloss( def to_parts( self, - freecad_path: str = "C:/Program Files/FreeCAD 0.19/bin", + freecad_path: str = get_freecad_path(), tol: float = 0.1, spacer_thickness: float = 0.0, ): @@ -270,7 +271,7 @@ def to_step( name: str, spacer_thickness: float = 0.0, tol: float = 0.1, - freecad_path: str = "C:/Program Files/FreeCAD 0.19/bin", + freecad_path: str = get_freecad_path(), ): # try and import the FreeCAD python extension diff --git a/planar_magnetics/geometry.py b/planar_magnetics/geometry.py index 71e70e6..ff5785b 100644 --- a/planar_magnetics/geometry.py +++ b/planar_magnetics/geometry.py @@ -4,6 +4,7 @@ from dataclasses import dataclass, field import math import uuid +from planar_magnetics.config import get_freecad_path # useful geometric constants TWO_PI = 2 * math.pi @@ -300,7 +301,7 @@ def to_pwl_path(self, max_angle: float = math.pi / 36): return points def to_wire( - self, z=0, closed=True, freecad_path: str = "C:/Program Files/FreeCAD 0.19/bin" + self, z=0, closed=True, freecad_path: str = get_freecad_path() ): """Convert the polygon to a FreeCAD Wire""" diff --git a/planar_magnetics/transformers/transformers.py b/planar_magnetics/transformers/transformers.py index b2e7086..2bd8c66 100644 --- a/planar_magnetics/transformers/transformers.py +++ b/planar_magnetics/transformers/transformers.py @@ -2,6 +2,7 @@ from planar_magnetics.geometry import Point from planar_magnetics.windings import Spiral from planar_magnetics.cores import Core +from planar_magnetics.config import get_freecad_path from planar_magnetics.kicad import Footprint, Reference, Value @@ -61,7 +62,7 @@ def to_kicad_footprint( self, name: str, create_core_step: bool = False, - freecad_path: str = "C:/Program Files/FreeCAD 0.19/bin", + freecad_path: str = get_freecad_path(), ): """Export the Cffc inductor design as a KiCAD footprint file (*.kicad_mods)""" diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..36e010f --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,37 @@ +import os +from planar_magnetics.config import get_freecad_path, DEFAULT_FREECAD_PATH + + +def test_get_freecad_path_default(): + """Test that get_freecad_path returns the default path when no env var is set.""" + # Temporarily clear the environment variable if it exists + original_value = os.environ.pop("FREECAD_PATH", None) + try: + # Test that the default path is returned + assert get_freecad_path() == DEFAULT_FREECAD_PATH + finally: + # Restore the environment variable if it existed + if original_value is not None: + os.environ["FREECAD_PATH"] = original_value + + +def test_get_freecad_path_from_env(monkeypatch): + """Test that get_freecad_path returns the value from environment variable when set.""" + # Test path value + test_path = "/custom/path/to/freecad" + + # Set the environment variable to our test value + monkeypatch.setenv("FREECAD_PATH", test_path) + + # Test that the function returns our custom path + assert get_freecad_path() == test_path + + +def test_default_freecad_path_format(): + """Test that the default path follows expected format.""" + # Ensure the path is a string + assert isinstance(DEFAULT_FREECAD_PATH, str) + + # Check that it contains expected FreeCAD path elements + assert "FreeCAD" in DEFAULT_FREECAD_PATH + assert "bin" in DEFAULT_FREECAD_PATH diff --git a/tests/test_geometry.py b/tests/test_geometry.py index d812947..bc1e51a 100644 --- a/tests/test_geometry.py +++ b/tests/test_geometry.py @@ -1,5 +1,19 @@ import math -from planar_magnetics.geometry import Point, get_distance +import pytest +import sys +from planar_magnetics.geometry import Point, Polygon, get_distance +from planar_magnetics.config import get_freecad_path + + +# Skip test if FreeCAD is not available +def is_freecad_available(): + try: + freecad_path = get_freecad_path() + sys.path.append(freecad_path) + import FreeCAD # noqa: F401 + return True + except (ImportError, ModuleNotFoundError): + return False def test_get_distance(): @@ -10,5 +24,47 @@ def test_get_distance(): assert math.isclose(distance, 1) +@pytest.mark.skipif(not is_freecad_available(), reason="FreeCAD not available") +def test_polygon_to_wire(): + """Test the Polygon.to_wire method that converts to a FreeCAD wire.""" + # Create a simple square polygon + p0 = Point(0, 0) + p1 = Point(10, 0) + p2 = Point(10, 10) + p3 = Point(0, 10) + polygon = Polygon([p0, p1, p2, p3]) + + # Get the Wire + wire = polygon.to_wire() + + # Import FreeCAD again (for assertions) + freecad_path = get_freecad_path() + sys.path.append(freecad_path) + import FreeCAD # noqa: F401 + import Part + + # Verify it's a valid Wire object + assert isinstance(wire, Part.Wire) + + # Verify the number of edges (should be 4 for a closed square) + assert len(wire.Edges) == 4 + + # Verify it's closed + assert wire.isClosed() + + # Verify its length (perimeter should be 40 units) + assert math.isclose(wire.Length, 40.0, rel_tol=1e-9) + + # Test with closed=False + open_wire = polygon.to_wire(closed=False) + assert len(open_wire.Edges) == 3 # Should have 3 edges if not closed + assert not open_wire.isClosed() + + # Test with z-height + z_wire = polygon.to_wire(z=5) + for vertex in z_wire.Vertexes: + assert math.isclose(vertex.Z, 5.0, rel_tol=1e-9) + + if __name__ == "__main__": test_get_distance() From a23cf0beab0cf6e67a5b7489bee076dcbb5809ce Mon Sep 17 00:00:00 2001 From: Ryan Wellborn Date: Mon, 19 May 2025 07:03:09 -0600 Subject: [PATCH 2/2] build: Updated package version to v0.1.7 --- CHANGELOG.md | 3 ++- setup.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd38ae0..b373241 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased] +## [v0.1.7] ### Fixed -Fix [issue-16](https://github.com/dzimmanck/python-planar-magnetics/issues/16). The estimate_dcr method is now defined in the Winding class and inherited by all winding classes. -Fix [issue-18](https://github.com/dzimmanck/python-planar-magnetics/issues/18). Mutable default values in kicad.py dataclasses. +-Feature [issue-21](https://github.com/dzimmanck/python-planar-magnetics/issues/21). Updated FreeCAD paths throughout package to reference a configurable environment variable. ### Added diff --git a/setup.py b/setup.py index 1b52579..cd308a0 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="planar-magnetics", - version="0.1.6", + version="0.1.7", author="Donny Zimmanck", author_email="dzimmanck@gmail.com", description="Create planar magnetic structures programmatically and export to CAD tools.",