TASK: Add Measurement class (#18)#48
TASK: Add Measurement class (#18)#48Poorna-Chandra-D wants to merge 3 commits intoTheGittyPerson:mainfrom
Measurement class (#18)#48Conversation
0002fff to
b6d0849
Compare
|
@Poorna-Chandra-D Since this is a duplicate of #46 (@P-r-e-m-i-u-m submitted the PR first but you started working first, I thought it would be unfair to choose one), are you interested in working with @P-r-e-m-i-u-m? It's totally fine if you prefer to work solo (@P-r-e-m-i-u-m has already worked on many PRs so don't feel guilty). If you want to collaborate with him, you may discuss with him in his PR (or tag him here). |
171f367 to
1ef13e7
Compare
|
Updated your branch 👍 |
1ef13e7 to
da2cc7a
Compare
- Add src/measurement.py with Measurement class that stores a value and unit - Measurement supports meters, centimeters, feet, and inches - Updated Person.height to use Measurement type instead of float - Added Person.set_height() method to set height with unit support - Updated introduce() to display height using Measurement string representation Closes TheGittyPerson#18 # Conflicts: # theperson/measurement.py # theperson/person.py # Conflicts (2nd rebase conflict): # theperson/person.py
da2cc7a to
beb8603
Compare
Signed-off-by: Morpheus <167074500+thegittyperson@users.noreply.github.com>
| TypeError: If value is not numeric or unit is not a string. | ||
| ValueError: If value is negative or unit is not recognized. | ||
| """ | ||
| if not isinstance(value, (int, float)): |
There was a problem hiding this comment.
Explicitly reject bool here as bool is a subclass of int and would pass this type check, which is unintended
| def __eq__(self, other: object) -> bool: | ||
| """Compare measurements by their value in meters.""" | ||
| if not isinstance(other, Measurement): | ||
| return NotImplemented | ||
| return isclose(self.to_meters(), other.to_meters(), rel_tol=0.0, | ||
| abs_tol=1e-9) | ||
|
|
||
| def __lt__(self, other: object) -> bool: | ||
| """Compare whether one measurement is smaller than another.""" | ||
| if not isinstance(other, Measurement): | ||
| return NotImplemented | ||
| return self.to_meters() < other.to_meters() |
There was a problem hiding this comment.
__eq__ is tolerant while __lt__ is not. Consider choosing one for consistency. I'd say have both use exact comparison.
Also, only __eq__ and __lt__ are implemented; operations like >= or <= will raise TypeError unless you add __le__, __gt__, __ge__ or use functools.total_ordering.
| """Return a human-readable string representation.""" | ||
| if precision < 0: | ||
| raise ValueError(f"Precision must be non-negative, got {precision}") | ||
| rounded_value = round(self.value, precision) |
There was a problem hiding this comment.
round() uses bankers rounding. for user-facing measurement strings you might want a specific rounding mode or formatting policy (or document it).
| if normalized not in cls.UNIT_ALIASES: | ||
| raise ValueError( | ||
| f"Unit '{unit}' is not recognized. " | ||
| f"Valid units are: {', '.join(cls.VALID_UNITS)}" |
There was a problem hiding this comment.
cls.VALID_UNITS only includes canonical units (meters, centimeters, feet, ...) and not their shortened forms (m, cm, ft, ...).
Consider adding those to VALID_UNITS or mention something somewhere in the error message.
| def set_height(self, value: float, unit: str = "meters") -> None: | ||
| """Set the person's height. | ||
|
|
||
| Args: | ||
| value: The numeric height value. Must be non-negative. | ||
| unit: The unit for the height. Defaults to 'meters'. | ||
| """ | ||
| self.physical.height = Measurement(value, unit) | ||
|
|
||
| def get_height_in(self, unit: str) -> Measurement: | ||
| """Return the person's height converted into a different unit. | ||
|
|
||
| Args: | ||
| unit: The target unit for conversion. | ||
|
|
||
| Raises: | ||
| ValueError: If height has not been set. | ||
| """ | ||
| if self.physical.height is None: | ||
| raise ValueError("Height has not been set") | ||
| return self.physical.height.to_unit(unit) |
There was a problem hiding this comment.
I feel like these methods don't belong here... Perhaps move them to the Physical data class above. Let me know what you think here.
Measurement class (#18)
Summary
Adds a
Measurementclass to represent a numeric measurement with a unit (meters, centimeters, feet, inches), and integrates it into thePersonclass to replace the barefloatheight attribute.Changes
src/measurement.py— addsMeasurementclass with:valueandunitattributesmeters,centimeters,feet,inches)__str__returning a human-readable representation (1.8 meters)__repr__for developer conveniencesrc/person.py:heightattribute type changed fromfloat | NonetoMeasurement | Noneintroduce()displaysself.heightnaturally viastr(Measurement)outputset_height(value, unit)method for convenient height assignment.Usage
Closes #18