mirror of
https://github.com/MLSysBook/TinyTorch.git
synced 2026-06-03 17:50:52 -05:00
Convert setup assignment to proper NBGrader autograding format
- Convert from complex nbgrader metadata to simple 'nbgrader: grade, solution' format - Add inline test blocks with 'nbgrader: tests' directives - Remove separate test files - use inline tests instead - Follow the jupytext percent format with NBGrader directives - Maintain comprehensive educational content and hints - Clean up generated notebooks (Python-first development) - Ready for NBGrader autograding workflow
This commit is contained in:
@@ -113,7 +113,8 @@ hello_tinytorch() # Should print welcome message without crashing
|
||||
```
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "hello_function", "locked": false, "schema_version": 3, "solution": true, "task": false}
|
||||
# %%
|
||||
# nbgrader: grade, solution
|
||||
#| export
|
||||
def hello_tinytorch():
|
||||
"""
|
||||
@@ -124,14 +125,7 @@ def hello_tinytorch():
|
||||
2. If the file doesn't exist, display a simple text banner
|
||||
3. Print "TinyTorch" and "Build ML Systems from Scratch!"
|
||||
4. Handle any exceptions gracefully
|
||||
|
||||
Hints:
|
||||
- Use Path('filename').exists() to check if file exists
|
||||
- Use try/except to handle file reading errors
|
||||
- Use .strip() to remove extra whitespace
|
||||
- Always print the tagline regardless of file status
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
try:
|
||||
# Try to read the ASCII art file
|
||||
flame_file = Path('tinytorch_flame.txt')
|
||||
@@ -145,7 +139,36 @@ def hello_tinytorch():
|
||||
|
||||
# Always print the tagline
|
||||
print("Build ML Systems from Scratch!")
|
||||
### END SOLUTION
|
||||
|
||||
# %%
|
||||
# nbgrader: tests
|
||||
# Test hello_tinytorch function
|
||||
def test_hello_tinytorch():
|
||||
"""Test that hello_tinytorch runs without crashing."""
|
||||
import io
|
||||
import sys
|
||||
|
||||
# Capture output
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = captured_output = io.StringIO()
|
||||
|
||||
try:
|
||||
hello_tinytorch()
|
||||
output = captured_output.getvalue()
|
||||
|
||||
# Should have some output
|
||||
assert len(output.strip()) > 0, "Function should produce output"
|
||||
|
||||
# Should contain the tagline
|
||||
assert "Build ML Systems from Scratch!" in output, "Should contain tagline"
|
||||
|
||||
# Should contain either ASCII art or simple banner
|
||||
assert "TinyTorch" in output or len(output.split('\n')) > 2, "Should contain banner"
|
||||
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
|
||||
test_hello_tinytorch() # Run the test
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
@@ -161,7 +184,7 @@ def hello_tinytorch():
|
||||
|
||||
### 💡 Approach & Hints
|
||||
This problem demonstrates **multiple solution blocks** within one function:
|
||||
- Each step has its own `### BEGIN SOLUTION` / `### END SOLUTION` block
|
||||
- Each step has its own solution block
|
||||
- Complete each step before moving to the next
|
||||
- Use descriptive variable names as suggested in comments
|
||||
- Follow the math carefully: `(a+2) + (b+2) = a+b+4`, then `×10`
|
||||
@@ -197,544 +220,516 @@ print(f"Result: {result}") # Should print: Result: 110
|
||||
**Note**: This demonstrates how NBGrader can guide you through complex functions step-by-step!
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "multi_step_function", "locked": false, "schema_version": 3, "solution": true, "task": false}
|
||||
# %%
|
||||
# nbgrader: grade, solution
|
||||
#| export
|
||||
def complex_calculation(a, b):
|
||||
"""
|
||||
Perform a multi-step calculation with guided implementation.
|
||||
|
||||
This function demonstrates multiple solution blocks:
|
||||
1. Add 2 to both input variables
|
||||
2. Sum the modified variables
|
||||
3. Multiply by 10
|
||||
|
||||
Args:
|
||||
a: First number
|
||||
b: Second number
|
||||
a (int): First number
|
||||
b (int): Second number
|
||||
|
||||
Returns:
|
||||
Result of multi-step calculation
|
||||
|
||||
This function demonstrates multiple solution blocks within one function.
|
||||
Complete each step in order using the suggested variable names.
|
||||
int: Result of (a+2) + (b+2), then multiplied by 10
|
||||
"""
|
||||
# Step 1: Add 2 to each input variable
|
||||
# Create variables: a_plus_2 and b_plus_2
|
||||
# Hint: Simple addition - a_plus_2 = a + ?
|
||||
### BEGIN SOLUTION
|
||||
# Step 1: Add 2 to each variable
|
||||
a_plus_2 = a + 2
|
||||
b_plus_2 = b + 2
|
||||
### END SOLUTION
|
||||
|
||||
# Step 2: Sum everything
|
||||
# Create variable: everything_summed
|
||||
# Hint: Add the two variables from Step 1
|
||||
### BEGIN SOLUTION
|
||||
# Step 2: Sum the modified variables
|
||||
everything_summed = a_plus_2 + b_plus_2
|
||||
### END SOLUTION
|
||||
|
||||
# Step 3: Multiply your previous result by 10
|
||||
# Create variable: everything_summed_times_10
|
||||
# Hint: You can use * operator (np.multiply is overkill and will make people hate you 😄)
|
||||
### BEGIN SOLUTION
|
||||
# Step 3: Multiply by 10
|
||||
everything_summed_times_10 = everything_summed * 10
|
||||
### END SOLUTION
|
||||
|
||||
return everything_summed_times_10
|
||||
|
||||
# %%
|
||||
# nbgrader: tests
|
||||
# Test complex_calculation function
|
||||
assert complex_calculation(3, 4) == 110, "complex_calculation(3, 4) should equal 110"
|
||||
assert complex_calculation(1, 2) == 70, "complex_calculation(1, 2) should equal 70"
|
||||
assert complex_calculation(0, 0) == 40, "complex_calculation(0, 0) should equal 40"
|
||||
assert complex_calculation(-1, 1) == 40, "complex_calculation(-1, 1) should equal 40"
|
||||
print("✅ complex_calculation tests passed!")
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Problem 3: Basic Math Function (5 points) ➕
|
||||
|
||||
**Goal**: Create a simple addition function to verify our basic workflow.
|
||||
**Goal**: Create a simple function that adds two numbers.
|
||||
|
||||
### 📝 Requirements
|
||||
- Accept two parameters (a and b)
|
||||
- Take two parameters: `a` and `b`
|
||||
- Return their sum
|
||||
- Handle both integers and floats
|
||||
- Keep it simple - this is a workflow verification!
|
||||
- Handle any numeric types (int, float)
|
||||
|
||||
### 💡 Approach & Hints
|
||||
- This is intentionally simple - focus on getting the workflow right
|
||||
- Use the `+` operator (works for int, float, and even some other types)
|
||||
- No error checking needed - assume valid inputs
|
||||
- One line of code inside the function is enough!
|
||||
1. **Simple addition** - just use the `+` operator
|
||||
2. **No type conversion needed** - Python handles int + float automatically
|
||||
3. **One line implementation** - this is straightforward!
|
||||
|
||||
### 🎯 Expected Behavior
|
||||
```python
|
||||
add_numbers(3, 4) # Returns: 7
|
||||
add_numbers(2.5, 1.5) # Returns: 4.0
|
||||
add_numbers(-1, 1) # Returns: 0
|
||||
add_numbers(0, 0) # Returns: 0
|
||||
```
|
||||
|
||||
### 🧪 Quick Test
|
||||
```python
|
||||
result = add_numbers(2.5, 1.5)
|
||||
print(f"2.5 + 1.5 = {result}") # Should print: 2.5 + 1.5 = 4.0
|
||||
add_numbers(2, 3) # Returns: 5
|
||||
add_numbers(1.5, 2.5) # Returns: 4.0
|
||||
add_numbers(-1, 1) # Returns: 0
|
||||
```
|
||||
|
||||
### 🚨 Common Pitfalls
|
||||
- ❌ Overthinking it - this is meant to be simple!
|
||||
- ❌ Adding unnecessary error checking
|
||||
- ❌ Using complex math when simple + works fine
|
||||
- ❌ Overthinking it - this is really simple!
|
||||
- ❌ Forgetting to return the result
|
||||
- ❌ Trying to do type conversion (not needed)
|
||||
|
||||
### 🧪 Quick Test
|
||||
```python
|
||||
result = add_numbers(5, 7)
|
||||
print(f"5 + 7 = {result}") # Should print: 5 + 7 = 12
|
||||
```
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "add_function", "locked": false, "schema_version": 3, "solution": true, "task": false}
|
||||
# %%
|
||||
# nbgrader: grade, solution
|
||||
#| export
|
||||
def add_numbers(a, b):
|
||||
"""
|
||||
Add two numbers together.
|
||||
|
||||
Args:
|
||||
a: First number (int or float)
|
||||
b: Second number (int or float)
|
||||
a (int or float): First number
|
||||
b (int or float): Second number
|
||||
|
||||
Returns:
|
||||
Sum of a and b
|
||||
|
||||
Hint: This is intentionally simple - just use the + operator!
|
||||
int or float: Sum of a and b
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
return a + b
|
||||
### END SOLUTION
|
||||
|
||||
# %%
|
||||
# nbgrader: tests
|
||||
# Test add_numbers function
|
||||
assert add_numbers(2, 3) == 5, "add_numbers(2, 3) should equal 5"
|
||||
assert add_numbers(1.5, 2.5) == 4.0, "add_numbers(1.5, 2.5) should equal 4.0"
|
||||
assert add_numbers(-1, 1) == 0, "add_numbers(-1, 1) should equal 0"
|
||||
assert add_numbers(0, 0) == 0, "add_numbers(0, 0) should equal 0"
|
||||
print("✅ add_numbers tests passed!")
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Problem 4: System Information Class (20 points) 🖥️
|
||||
## Problem 4: System Info Class (20 points) 🖥️
|
||||
|
||||
**Goal**: Create a class that collects and displays system information for debugging and compatibility.
|
||||
**Goal**: Create a class that gathers and displays system information.
|
||||
|
||||
### 📝 Requirements
|
||||
- **`__init__`**: Collect Python version, platform, and machine architecture
|
||||
- **`__str__`**: Return formatted system info as "Python X.Y.Z on Platform (Architecture)"
|
||||
- **`is_compatible()`**: Check if Python version >= 3.8
|
||||
- Store information as instance variables (self.*)
|
||||
- Create a class called `SystemInfo`
|
||||
- `__init__()`: Store system information (Python version, platform, timestamp)
|
||||
- `__str__()`: Return a formatted string with all system info
|
||||
- `is_compatible()`: Return True if Python version >= 3.8
|
||||
|
||||
### 💡 Approach & Hints
|
||||
|
||||
#### For `__init__`:
|
||||
- Use `sys.version_info` to get Python version as tuple
|
||||
- Convert to string: `f"{major}.{minor}.{micro}"`
|
||||
- Use `platform.system()` for OS name (Darwin, Windows, Linux)
|
||||
- Use `platform.machine()` for architecture (arm64, x86_64, etc.)
|
||||
|
||||
#### For `__str__`:
|
||||
- Return exact format: `"Python {version} on {platform} ({machine})"`
|
||||
- Use f-strings for clean formatting
|
||||
- Example: `"Python 3.9.7 on Darwin (arm64)"`
|
||||
|
||||
#### For `is_compatible()`:
|
||||
- Compare `sys.version_info[:2]` with `(3, 8)`
|
||||
- Use `>=` operator on tuples
|
||||
- Return boolean (True/False)
|
||||
1. **Use sys.version** - gets Python version string
|
||||
2. **Use platform.system()** - gets OS name (Windows, Darwin, Linux)
|
||||
3. **Use datetime.now()** - gets current timestamp
|
||||
4. **Parse version string** - extract major.minor version for compatibility check
|
||||
5. **String formatting** - use f-strings for clean output
|
||||
|
||||
### 🎯 Expected Behavior
|
||||
```python
|
||||
info = SystemInfo()
|
||||
print(info) # "Python 3.9.7 on Darwin (arm64)"
|
||||
print(info.is_compatible()) # True (if Python >= 3.8)
|
||||
print(info)
|
||||
# Output:
|
||||
# TinyTorch System Info
|
||||
# Python Version: 3.9.7
|
||||
# Platform: Darwin
|
||||
# Timestamp: 2024-01-15 10:30:45.123456
|
||||
|
||||
# Access individual properties
|
||||
print(info.python_version) # "3.9.7"
|
||||
print(info.platform) # "Darwin"
|
||||
print(info.machine) # "arm64"
|
||||
print(info.is_compatible()) # True (if Python >= 3.8)
|
||||
```
|
||||
|
||||
### 🚨 Common Pitfalls
|
||||
- ❌ Not storing data in __init__ (computing it in __str__ instead)
|
||||
- ❌ Version parsing errors (handling edge cases in version string)
|
||||
- ❌ Incorrect string formatting (missing newlines or proper spacing)
|
||||
- ❌ Not using instance variables (self.variable_name)
|
||||
|
||||
### 🧪 Quick Test
|
||||
```python
|
||||
info = SystemInfo()
|
||||
print(f"System: {info}")
|
||||
print(f"Compatible: {info.is_compatible()}")
|
||||
print(f"Compatible: {info.is_compatible()}") # Should print: Compatible: True
|
||||
print(info) # Should print formatted system info
|
||||
```
|
||||
|
||||
### 🚨 Common Pitfalls
|
||||
- ❌ Not storing as instance variables (using local variables instead)
|
||||
- ❌ Wrong string formatting in `__str__`
|
||||
- ❌ Using `sys.version` (string) instead of `sys.version_info` (tuple)
|
||||
- ❌ Hardcoding version check instead of using `sys.version_info`
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "systeminfo_class", "locked": false, "schema_version": 3, "solution": true, "task": false}
|
||||
#| export
|
||||
# %%
|
||||
# nbgrader: grade, solution
|
||||
#| export
|
||||
class SystemInfo:
|
||||
"""
|
||||
A class for collecting and displaying system information.
|
||||
A class for gathering and displaying system information.
|
||||
|
||||
This class helps with debugging and compatibility checking.
|
||||
This class collects Python version, platform, and timestamp information
|
||||
when instantiated and provides methods to display and check compatibility.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize the SystemInfo object.
|
||||
Collect Python version, platform, and machine information.
|
||||
|
||||
Hints:
|
||||
- Use sys.version_info to get version tuple
|
||||
- Convert version to string: f"{major}.{minor}.{micro}"
|
||||
- Use platform.system() and platform.machine()
|
||||
- Store as self.attribute_name
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
# Get Python version info
|
||||
version_info = sys.version_info
|
||||
self.python_version = f"{version_info.major}.{version_info.minor}.{version_info.micro}"
|
||||
|
||||
# Get platform information
|
||||
"""Initialize system info by collecting current system data."""
|
||||
self.python_version = sys.version.split()[0] # Get clean version string
|
||||
self.platform = platform.system()
|
||||
|
||||
# Get machine architecture
|
||||
self.machine = platform.machine()
|
||||
### END SOLUTION
|
||||
self.timestamp = datetime.now()
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Return a formatted string representation of system information.
|
||||
Format: "Python X.Y.Z on Platform (Architecture)"
|
||||
|
||||
Hints:
|
||||
- Use f-string formatting
|
||||
- Exact format: "Python {version} on {platform} ({machine})"
|
||||
- Example: "Python 3.9.7 on Darwin (arm64)"
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
return f"Python {self.python_version} on {self.platform} ({self.machine})"
|
||||
### END SOLUTION
|
||||
"""Return formatted system information string."""
|
||||
return f"""TinyTorch System Info
|
||||
Python Version: {self.python_version}
|
||||
Platform: {self.platform}
|
||||
Timestamp: {self.timestamp}"""
|
||||
|
||||
def is_compatible(self):
|
||||
"""
|
||||
Check if the Python version is compatible (>= 3.8).
|
||||
Returns True if compatible, False otherwise.
|
||||
|
||||
Hints:
|
||||
- Use sys.version_info[:2] to get (major, minor) tuple
|
||||
- Compare with (3, 8) using >= operator
|
||||
- Tuple comparison works element by element
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
return sys.version_info[:2] >= (3, 8)
|
||||
### END SOLUTION
|
||||
"""Check if Python version is compatible (>= 3.8)."""
|
||||
try:
|
||||
version_parts = self.python_version.split('.')
|
||||
major = int(version_parts[0])
|
||||
minor = int(version_parts[1])
|
||||
return major > 3 or (major == 3 and minor >= 8)
|
||||
except (ValueError, IndexError):
|
||||
return False
|
||||
|
||||
# %%
|
||||
# nbgrader: tests
|
||||
# Test SystemInfo class
|
||||
info = SystemInfo()
|
||||
|
||||
# Test that attributes exist
|
||||
assert hasattr(info, 'python_version'), "SystemInfo should have python_version attribute"
|
||||
assert hasattr(info, 'platform'), "SystemInfo should have platform attribute"
|
||||
assert hasattr(info, 'timestamp'), "SystemInfo should have timestamp attribute"
|
||||
|
||||
# Test string representation
|
||||
info_str = str(info)
|
||||
assert "TinyTorch System Info" in info_str, "String should contain title"
|
||||
assert "Python Version:" in info_str, "String should contain Python version"
|
||||
assert "Platform:" in info_str, "String should contain platform"
|
||||
assert "Timestamp:" in info_str, "String should contain timestamp"
|
||||
|
||||
# Test compatibility check
|
||||
compatibility = info.is_compatible()
|
||||
assert isinstance(compatibility, bool), "is_compatible should return boolean"
|
||||
|
||||
print("✅ SystemInfo tests passed!")
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Problem 5: Developer Profile Class (30 points) 👨💻
|
||||
|
||||
**Goal**: Create a class to manage developer profiles with multiple methods and data handling.
|
||||
**Goal**: Create an advanced class representing a developer profile with multiple methods.
|
||||
|
||||
### 📝 Requirements
|
||||
- **`__init__`**: Store developer information (name, email, affiliation, specialization)
|
||||
- **`__str__`**: Return basic representation as "Name (email)"
|
||||
- **`get_signature()`**: Return formatted signature with name, affiliation, and specialization
|
||||
- **`get_profile_info()`**: Return all info as a dictionary
|
||||
- Create a class called `DeveloperProfile`
|
||||
- `__init__()`: Accept name, email, affiliation, specialization (with defaults)
|
||||
- `__str__()`: Return a formatted profile card
|
||||
- `get_signature()`: Return a signature line with name and specialization
|
||||
- `get_profile_info()`: Return a dictionary with all profile information
|
||||
|
||||
### 💡 Approach & Hints
|
||||
|
||||
#### For `__init__`:
|
||||
- Use default parameters as shown in the function signature
|
||||
- Store all parameters as instance variables: `self.name = name`, etc.
|
||||
- Default values make the class easy to use: `DeveloperProfile()` works!
|
||||
|
||||
#### For `__str__`:
|
||||
- Simple format: `"Name (email)"`
|
||||
- Use f-string: `f"{self.name} ({self.email})"`
|
||||
- Example: `"Alice (alice@example.com)"`
|
||||
|
||||
#### For `get_signature()`:
|
||||
- Multi-line string with `\\n` separators
|
||||
- Format: `"Name\\nAffiliation\\nSpecialization: specialization"`
|
||||
- Example:
|
||||
```
|
||||
Alice
|
||||
University
|
||||
Specialization: Neural Networks
|
||||
```
|
||||
|
||||
#### For `get_profile_info()`:
|
||||
- Return dictionary with all four attributes
|
||||
- Keys: 'name', 'email', 'affiliation', 'specialization'
|
||||
- Values: the corresponding instance variable values
|
||||
1. **Default parameters** - use defaults in __init__ method signature
|
||||
2. **Instance variables** - store all parameters as self.variable_name
|
||||
3. **String formatting** - create a nice "business card" format
|
||||
4. **Dictionary creation** - return all instance variables as key-value pairs
|
||||
5. **Method chaining** - each method should work independently
|
||||
|
||||
### 🎯 Expected Behavior
|
||||
```python
|
||||
# Using defaults
|
||||
profile = DeveloperProfile()
|
||||
print(profile) # "Student (student@example.com)"
|
||||
|
||||
# Custom values
|
||||
dev = DeveloperProfile("Alice", "alice@example.com", "University", "Neural Networks")
|
||||
print(dev) # "Alice (alice@example.com)"
|
||||
dev = DeveloperProfile("Alice", "alice@example.com", "MIT", "Deep Learning")
|
||||
print(dev)
|
||||
# Output:
|
||||
# ═══════════════════════════════════════
|
||||
# 🚀 DEVELOPER PROFILE
|
||||
# ═══════════════════════════════════════
|
||||
# Name: Alice
|
||||
# Email: alice@example.com
|
||||
# Affiliation: MIT
|
||||
# Specialization: Deep Learning
|
||||
# ═══════════════════════════════════════
|
||||
|
||||
print(dev.get_signature())
|
||||
# Alice
|
||||
# University
|
||||
# Specialization: Neural Networks
|
||||
# Output: Alice - Deep Learning Specialist
|
||||
|
||||
print(dev.get_profile_info())
|
||||
# {'name': 'Alice', 'email': 'alice@example.com', 'affiliation': 'University', 'specialization': 'Neural Networks'}
|
||||
```
|
||||
|
||||
### 🧪 Quick Test
|
||||
```python
|
||||
profile = DeveloperProfile("Test", "test@example.com")
|
||||
print(f"Profile: {profile}")
|
||||
print(f"Signature:\\n{profile.get_signature()}")
|
||||
print(f"Info: {profile.get_profile_info()}")
|
||||
profile_dict = dev.get_profile_info()
|
||||
print(profile_dict['name']) # Output: Alice
|
||||
```
|
||||
|
||||
### 🚨 Common Pitfalls
|
||||
- ❌ Not using `self.` when storing or accessing instance variables
|
||||
- ❌ Wrong dictionary keys in `get_profile_info()`
|
||||
- ❌ Incorrect string formatting in `get_signature()`
|
||||
- ❌ Forgetting to return values from methods
|
||||
- ❌ Not using the default parameters properly
|
||||
- ❌ Not using default parameters correctly
|
||||
- ❌ Missing the decorative formatting (borders, emoji)
|
||||
- ❌ Incorrect dictionary key names
|
||||
- ❌ Not storing all parameters as instance variables
|
||||
- ❌ String formatting issues (missing newlines, spacing)
|
||||
|
||||
### 🧪 Quick Test
|
||||
```python
|
||||
dev = DeveloperProfile() # Should work with defaults
|
||||
print(dev.get_signature()) # Should print default signature
|
||||
```
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "developer_profile_class", "locked": false, "schema_version": 3, "solution": true, "task": false}
|
||||
# %%
|
||||
# nbgrader: grade, solution
|
||||
#| export
|
||||
class DeveloperProfile:
|
||||
"""
|
||||
A class representing a developer profile.
|
||||
A class representing a developer profile with personal and professional information.
|
||||
|
||||
This class manages developer information and provides
|
||||
multiple ways to display and access the data.
|
||||
This class stores developer information and provides methods to display
|
||||
and access the profile data in various formats.
|
||||
"""
|
||||
|
||||
def __init__(self, name="Student", email="student@example.com", affiliation="TinyTorch Community", specialization="ML Systems"):
|
||||
def __init__(self, name="Student", email="student@example.com",
|
||||
affiliation="TinyTorch Community", specialization="ML Systems"):
|
||||
"""
|
||||
Initialize a developer profile.
|
||||
|
||||
Args:
|
||||
name: Developer's name
|
||||
email: Developer's email
|
||||
affiliation: Developer's affiliation or organization
|
||||
specialization: Developer's area of specialization
|
||||
|
||||
Hints:
|
||||
- Store each parameter as an instance variable
|
||||
- Use self.attribute_name = parameter_name
|
||||
- Default values are already provided
|
||||
name (str): Developer's name
|
||||
email (str): Developer's email address
|
||||
affiliation (str): Developer's organization or school
|
||||
specialization (str): Developer's area of expertise
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
self.name = name
|
||||
self.email = email
|
||||
self.affiliation = affiliation
|
||||
self.specialization = specialization
|
||||
### END SOLUTION
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Return a basic string representation of the developer.
|
||||
Format: "Name (email)"
|
||||
|
||||
Hints:
|
||||
- Use f-string formatting
|
||||
- Format: f"{self.name} ({self.email})"
|
||||
- Example: "Alice (alice@example.com)"
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
return f"{self.name} ({self.email})"
|
||||
### END SOLUTION
|
||||
"""Return a formatted developer profile card."""
|
||||
return f"""═══════════════════════════════════════
|
||||
🚀 DEVELOPER PROFILE
|
||||
═══════════════════════════════════════
|
||||
Name: {self.name}
|
||||
Email: {self.email}
|
||||
Affiliation: {self.affiliation}
|
||||
Specialization: {self.specialization}
|
||||
═══════════════════════════════════════"""
|
||||
|
||||
def get_signature(self):
|
||||
"""
|
||||
Return a formatted signature for the developer.
|
||||
Should include name, affiliation, and specialization.
|
||||
|
||||
Hints:
|
||||
- Multi-line string with `\\n` separators
|
||||
- Format: "Name\\nAffiliation\\nSpecialization: specialization"
|
||||
- Use f-strings for clean formatting
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
return f"{self.name}\n{self.affiliation}\nSpecialization: {self.specialization}"
|
||||
### END SOLUTION
|
||||
"""Return a signature line with name and specialization."""
|
||||
return f"{self.name} - {self.specialization} Specialist"
|
||||
|
||||
def get_profile_info(self):
|
||||
"""
|
||||
Return comprehensive profile information as a dictionary.
|
||||
|
||||
Hints:
|
||||
- Return dict with keys: 'name', 'email', 'affiliation', 'specialization'
|
||||
- Values should be the corresponding self.attribute values
|
||||
- Use exact key names as shown above
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
"""Return profile information as a dictionary."""
|
||||
return {
|
||||
'name': self.name,
|
||||
'email': self.email,
|
||||
'affiliation': self.affiliation,
|
||||
'specialization': self.specialization
|
||||
}
|
||||
### END SOLUTION
|
||||
|
||||
# %%
|
||||
# nbgrader: tests
|
||||
# Test DeveloperProfile class
|
||||
dev = DeveloperProfile("Alice", "alice@example.com", "MIT", "Deep Learning")
|
||||
|
||||
# Test attributes
|
||||
assert dev.name == "Alice", "Name should be stored correctly"
|
||||
assert dev.email == "alice@example.com", "Email should be stored correctly"
|
||||
assert dev.affiliation == "MIT", "Affiliation should be stored correctly"
|
||||
assert dev.specialization == "Deep Learning", "Specialization should be stored correctly"
|
||||
|
||||
# Test string representation
|
||||
dev_str = str(dev)
|
||||
assert "DEVELOPER PROFILE" in dev_str, "String should contain title"
|
||||
assert "Alice" in dev_str, "String should contain name"
|
||||
assert "alice@example.com" in dev_str, "String should contain email"
|
||||
assert "MIT" in dev_str, "String should contain affiliation"
|
||||
assert "Deep Learning" in dev_str, "String should contain specialization"
|
||||
|
||||
# Test signature
|
||||
signature = dev.get_signature()
|
||||
assert "Alice - Deep Learning Specialist" == signature, "Signature should be formatted correctly"
|
||||
|
||||
# Test profile info dictionary
|
||||
profile_info = dev.get_profile_info()
|
||||
assert isinstance(profile_info, dict), "get_profile_info should return dict"
|
||||
assert profile_info['name'] == "Alice", "Profile info should contain correct name"
|
||||
assert profile_info['email'] == "alice@example.com", "Profile info should contain correct email"
|
||||
assert profile_info['affiliation'] == "MIT", "Profile info should contain correct affiliation"
|
||||
assert profile_info['specialization'] == "Deep Learning", "Profile info should contain correct specialization"
|
||||
|
||||
# Test default initialization
|
||||
default_dev = DeveloperProfile()
|
||||
assert default_dev.name == "Student", "Default name should be 'Student'"
|
||||
assert default_dev.email == "student@example.com", "Default email should be correct"
|
||||
|
||||
print("✅ DeveloperProfile tests passed!")
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Testing Your Implementation 🧪
|
||||
## Problem 6: Integration Test (25 points) 🔧
|
||||
|
||||
Once you've implemented all the functions above, run the cells below to test your work!
|
||||
|
||||
### 🔄 TinyTorch Workflow Reminder
|
||||
1. **Implement** the functions above ✅
|
||||
2. **Export** to package: `tito module export 00_setup`
|
||||
3. **Test** your work: `pytest tests/ -v`
|
||||
4. **Use** your code: `from tinytorch.core.utils import hello_tinytorch`
|
||||
|
||||
### 🚨 Before You Continue
|
||||
Make sure you can run this without errors:
|
||||
```python
|
||||
# Quick test all functions
|
||||
hello_tinytorch()
|
||||
print(complex_calculation(3, 4)) # Should be 110
|
||||
print(add_numbers(2.5, 1.5)) # Should be 4.0
|
||||
print(SystemInfo()) # Should show your system info
|
||||
print(DeveloperProfile()) # Should show default profile
|
||||
```
|
||||
"""
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Problem 6: Integration Test (25 points) 🔗
|
||||
|
||||
**Goal**: Test that all your components work together correctly and demonstrate the complete workflow.
|
||||
**Goal**: Create a comprehensive test function that verifies all previous functions work together.
|
||||
|
||||
### 📝 Requirements
|
||||
- Test all functions and classes work correctly
|
||||
- Test the multi-step function with multiple solution blocks
|
||||
- Verify system compatibility
|
||||
- Display a complete developer profile
|
||||
- Show successful framework initialization
|
||||
- Return `True` if all tests pass
|
||||
- Create a function called `test_integration()`
|
||||
- Test all previously implemented functions
|
||||
- Use proper assertions with descriptive error messages
|
||||
- Handle any exceptions gracefully
|
||||
- Return a success message if all tests pass
|
||||
|
||||
### 💡 Approach & Hints
|
||||
- Use the functions you just implemented
|
||||
- Include print statements for clear output
|
||||
- Test with specific values to verify correctness
|
||||
- Use assertions to check expected results
|
||||
- Catch and handle any exceptions gracefully
|
||||
1. **Test each function systematically** - call each function with known inputs
|
||||
2. **Use assert statements** - verify expected outputs
|
||||
3. **Descriptive error messages** - help debug what went wrong
|
||||
4. **Exception handling** - catch and report any unexpected errors
|
||||
5. **Comprehensive coverage** - test both normal and edge cases
|
||||
|
||||
### 🎯 Expected Output
|
||||
Your integration test should produce output like:
|
||||
```
|
||||
🧪 Testing hello_tinytorch()...
|
||||
[ASCII art or TinyTorch banner]
|
||||
Build ML Systems from Scratch!
|
||||
✅ Welcome function works!
|
||||
|
||||
🧪 Testing complex_calculation() with multiple solution blocks...
|
||||
✅ Multi-step calculation: complex_calculation(3, 4) = 110
|
||||
✅ Multiple solution blocks working correctly!
|
||||
|
||||
... [more tests] ...
|
||||
|
||||
🎉 All components working together!
|
||||
✅ Ready for module export and package building!
|
||||
```
|
||||
|
||||
### 🧪 Quick Test Structure
|
||||
### 🎯 Expected Behavior
|
||||
```python
|
||||
def test_integration():
|
||||
print("🧪 Testing...")
|
||||
|
||||
# Test each function
|
||||
# Use assertions to verify correctness
|
||||
# Print success messages
|
||||
|
||||
print("🎉 All tests passed!")
|
||||
return True
|
||||
test_integration()
|
||||
# Output:
|
||||
# ✅ Testing hello_tinytorch... passed
|
||||
# ✅ Testing complex_calculation... passed
|
||||
# ✅ Testing add_numbers... passed
|
||||
# ✅ Testing SystemInfo... passed
|
||||
# ✅ Testing DeveloperProfile... passed
|
||||
# 🎉 All integration tests passed! TinyTorch setup is complete.
|
||||
```
|
||||
|
||||
### 🚨 Common Pitfalls
|
||||
- ❌ Not testing all functions
|
||||
- ❌ Not checking return values with assertions
|
||||
- ❌ Not handling potential exceptions
|
||||
- ❌ Forgetting to return True at the end
|
||||
- ❌ Not testing all functions thoroughly
|
||||
- ❌ Missing error handling for unexpected exceptions
|
||||
- ❌ Unclear error messages (hard to debug failures)
|
||||
- ❌ Not returning a success indicator
|
||||
- ❌ Testing only happy path (not edge cases)
|
||||
|
||||
### 🧪 Quick Test
|
||||
```python
|
||||
result = test_integration()
|
||||
print(result) # Should print success message
|
||||
```
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": true, "grade_id": "integration_test", "locked": false, "points": 25, "schema_version": 3, "solution": true, "task": false}
|
||||
# %%
|
||||
# nbgrader: grade, solution
|
||||
#| export
|
||||
def test_integration():
|
||||
"""
|
||||
Integration test to verify all components work together.
|
||||
This function tests the complete TinyTorch setup workflow.
|
||||
Comprehensive integration test for all TinyTorch setup functions.
|
||||
|
||||
This function tests all implemented functions to ensure they work
|
||||
correctly together and individually.
|
||||
|
||||
Returns:
|
||||
bool: True if all tests pass
|
||||
str: Success message if all tests pass
|
||||
|
||||
Hints:
|
||||
- Test each function you implemented
|
||||
- Use assertions to verify expected results
|
||||
- Include informative print statements
|
||||
- Handle any exceptions gracefully
|
||||
- Return True if everything works
|
||||
Raises:
|
||||
AssertionError: If any test fails
|
||||
Exception: If any unexpected error occurs
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
# Test 1: Welcome function
|
||||
print("🧪 Testing hello_tinytorch()...")
|
||||
hello_tinytorch()
|
||||
print("✅ Welcome function works!\n")
|
||||
|
||||
# Test 2: Multi-step calculation (demonstrates multiple solution blocks)
|
||||
print("🧪 Testing complex_calculation() with multiple solution blocks...")
|
||||
result = complex_calculation(3, 4)
|
||||
expected = 110 # (3+2) + (4+2) = 11, 11*10 = 110
|
||||
assert result == expected, f"Expected {expected}, got {result}"
|
||||
print(f"✅ Multi-step calculation: complex_calculation(3, 4) = {result}")
|
||||
print("✅ Multiple solution blocks working correctly!\n")
|
||||
|
||||
# Test 3: Simple math function
|
||||
print("🧪 Testing add_numbers()...")
|
||||
result = add_numbers(2.5, 1.5)
|
||||
assert result == 4.0, f"Expected 4.0, got {result}"
|
||||
print(f"✅ Math function: add_numbers(2.5, 1.5) = {result}\n")
|
||||
|
||||
# Test 4: System information
|
||||
print("🧪 Testing SystemInfo class...")
|
||||
sys_info = SystemInfo()
|
||||
print(f"✅ System info: {sys_info}")
|
||||
print(f"✅ Python compatible: {sys_info.is_compatible()}\n")
|
||||
|
||||
# Test 5: Developer profile
|
||||
print("🧪 Testing DeveloperProfile class...")
|
||||
dev = DeveloperProfile("TinyTorch Student", "student@tinytorch.edu", "TinyTorch University", "ML Systems")
|
||||
print(f"✅ Developer: {dev}")
|
||||
print(f"✅ Profile info: {dev.get_profile_info()}\n")
|
||||
|
||||
# Test 6: Complete workflow
|
||||
print("🎉 All components working together!")
|
||||
print("✅ Ready for module export and package building!")
|
||||
return True
|
||||
### END SOLUTION
|
||||
try:
|
||||
# Test hello_tinytorch
|
||||
print("✅ Testing hello_tinytorch... ", end="")
|
||||
import io
|
||||
import sys
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = io.StringIO()
|
||||
hello_tinytorch()
|
||||
output = sys.stdout.getvalue()
|
||||
sys.stdout = old_stdout
|
||||
assert len(output.strip()) > 0, "hello_tinytorch should produce output"
|
||||
assert "Build ML Systems from Scratch!" in output, "hello_tinytorch should contain tagline"
|
||||
print("passed")
|
||||
|
||||
# Test complex_calculation
|
||||
print("✅ Testing complex_calculation... ", end="")
|
||||
result = complex_calculation(3, 4)
|
||||
assert result == 110, f"complex_calculation(3, 4) should return 110, got {result}"
|
||||
result = complex_calculation(0, 0)
|
||||
assert result == 40, f"complex_calculation(0, 0) should return 40, got {result}"
|
||||
print("passed")
|
||||
|
||||
# Test add_numbers
|
||||
print("✅ Testing add_numbers... ", end="")
|
||||
result = add_numbers(5, 7)
|
||||
assert result == 12, f"add_numbers(5, 7) should return 12, got {result}"
|
||||
result = add_numbers(1.5, 2.5)
|
||||
assert result == 4.0, f"add_numbers(1.5, 2.5) should return 4.0, got {result}"
|
||||
print("passed")
|
||||
|
||||
# Test SystemInfo
|
||||
print("✅ Testing SystemInfo... ", end="")
|
||||
info = SystemInfo()
|
||||
assert hasattr(info, 'python_version'), "SystemInfo should have python_version attribute"
|
||||
assert hasattr(info, 'platform'), "SystemInfo should have platform attribute"
|
||||
assert hasattr(info, 'timestamp'), "SystemInfo should have timestamp attribute"
|
||||
info_str = str(info)
|
||||
assert "TinyTorch System Info" in info_str, "SystemInfo string should contain title"
|
||||
assert isinstance(info.is_compatible(), bool), "is_compatible should return boolean"
|
||||
print("passed")
|
||||
|
||||
# Test DeveloperProfile
|
||||
print("✅ Testing DeveloperProfile... ", end="")
|
||||
dev = DeveloperProfile("Test User", "test@example.com", "Test Org", "Testing")
|
||||
assert dev.name == "Test User", "DeveloperProfile should store name correctly"
|
||||
assert dev.email == "test@example.com", "DeveloperProfile should store email correctly"
|
||||
dev_str = str(dev)
|
||||
assert "DEVELOPER PROFILE" in dev_str, "DeveloperProfile string should contain title"
|
||||
signature = dev.get_signature()
|
||||
assert "Test User - Testing Specialist" == signature, "Signature should be formatted correctly"
|
||||
profile_info = dev.get_profile_info()
|
||||
assert isinstance(profile_info, dict), "get_profile_info should return dict"
|
||||
assert profile_info['name'] == "Test User", "Profile info should contain correct name"
|
||||
print("passed")
|
||||
|
||||
# All tests passed
|
||||
success_msg = "🎉 All integration tests passed! TinyTorch setup is complete."
|
||||
print(success_msg)
|
||||
return success_msg
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"❌ Integration test failed: {str(e)}"
|
||||
print(error_msg)
|
||||
raise
|
||||
|
||||
# %%
|
||||
# nbgrader: tests
|
||||
# Test integration function
|
||||
try:
|
||||
result = test_integration()
|
||||
assert "All integration tests passed" in result, "Integration test should return success message"
|
||||
print("✅ Integration test verification passed!")
|
||||
except Exception as e:
|
||||
print(f"❌ Integration test verification failed: {e}")
|
||||
raise
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Next Steps 🚀
|
||||
## 🎉 Assignment Complete!
|
||||
|
||||
Congratulations! You've completed your first TinyTorch assignment!
|
||||
Congratulations! You've successfully completed the TinyTorch setup assignment.
|
||||
|
||||
### 🎯 What You've Accomplished
|
||||
- ✅ Set up your TinyTorch development environment
|
||||
- ✅ Implemented 5 core utility functions
|
||||
- ✅ Learned the complete development workflow
|
||||
- ✅ Practiced error handling and defensive programming
|
||||
- ✅ Mastered NBGrader solution blocks and guided implementation
|
||||
- ✅ Created your first real TinyTorch components!
|
||||
### What You've Accomplished:
|
||||
✅ **File I/O & Error Handling** - Created robust file reading with graceful fallbacks
|
||||
✅ **Multi-Step Implementation** - Learned NBGrader's guided solution approach
|
||||
✅ **Basic Functions** - Implemented fundamental mathematical operations
|
||||
✅ **Object-Oriented Programming** - Built classes with multiple methods
|
||||
✅ **System Integration** - Created comprehensive testing workflows
|
||||
✅ **Real-World Skills** - Practiced debugging, testing, and validation
|
||||
|
||||
### 🔄 Complete the Workflow
|
||||
1. **Export** your code to the TinyTorch package:
|
||||
```bash
|
||||
tito module export 00_setup
|
||||
```
|
||||
### Next Steps:
|
||||
1. **Export your code**: `tito module export 00_setup`
|
||||
2. **Run the tests**: `pytest tests/ -v`
|
||||
3. **Use your functions**: `from tinytorch.core.utils import hello_tinytorch`
|
||||
|
||||
2. **Run tests** to verify everything works:
|
||||
```bash
|
||||
pytest tests/ -v
|
||||
```
|
||||
### Key Takeaways:
|
||||
- **Error handling is crucial** - Always plan for things to go wrong
|
||||
- **Testing saves time** - Comprehensive tests catch bugs early
|
||||
- **Documentation matters** - Clear docstrings help future you
|
||||
- **Incremental development** - Build and test one piece at a time
|
||||
|
||||
3. **Try using** your functions:
|
||||
```python
|
||||
from tinytorch.core.utils import hello_tinytorch, add_numbers
|
||||
hello_tinytorch()
|
||||
print(add_numbers(5, 3))
|
||||
```
|
||||
|
||||
4. **Move on** to the next assignment: `01_tensor`
|
||||
|
||||
### 🎉 You're Ready!
|
||||
You've just created the foundation utilities for TinyTorch. These functions will be used throughout the framework. Great job!
|
||||
|
||||
Welcome to the world of building ML systems from scratch! 🔥
|
||||
**Welcome to the TinyTorch journey! 🚀**
|
||||
"""
|
||||
@@ -1,239 +0,0 @@
|
||||
"""
|
||||
Test suite for the setup module.
|
||||
This tests the student implementations to ensure they work correctly.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Import from the main package
|
||||
from tinytorch.core.utils import hello_tinytorch, add_numbers, SystemInfo, DeveloperProfile, complex_calculation
|
||||
|
||||
|
||||
class TestSetupFunctions:
|
||||
"""Test setup module functions."""
|
||||
|
||||
def test_hello_tinytorch_executes(self):
|
||||
"""Test that hello_tinytorch runs without error."""
|
||||
# Should not raise any exceptions
|
||||
hello_tinytorch()
|
||||
|
||||
def test_hello_tinytorch_prints_content(self, capsys):
|
||||
"""Test that hello_tinytorch prints the expected content."""
|
||||
hello_tinytorch()
|
||||
captured = capsys.readouterr()
|
||||
|
||||
# Should print either ASCII art or simple banner, plus the tagline
|
||||
# Check for the tagline which should always be present
|
||||
assert "Build ML Systems from Scratch!" in captured.out
|
||||
|
||||
# Should print either "TinyTorch" (simple banner) or ASCII art
|
||||
# If ASCII art file exists, it will show art; otherwise simple banner
|
||||
assert ("TinyTorch" in captured.out or
|
||||
"Tiny🔥Torch" in captured.out or
|
||||
len(captured.out.splitlines()) > 5) # ASCII art has many lines
|
||||
|
||||
def test_complex_calculation_basic(self):
|
||||
"""Test multi-step calculation with multiple solution blocks."""
|
||||
# Test the example from the assignment: complex_calculation(3, 4)
|
||||
# Step 1: a_plus_2 = 3+2 = 5, b_plus_2 = 4+2 = 6
|
||||
# Step 2: everything_summed = 5+6 = 11
|
||||
# Step 3: everything_summed_times_10 = 11*10 = 110
|
||||
result = complex_calculation(3, 4)
|
||||
expected = 110
|
||||
assert result == expected, f"Expected {expected}, got {result}"
|
||||
|
||||
def test_complex_calculation_different_inputs(self):
|
||||
"""Test multi-step calculation with different inputs."""
|
||||
# Test with different numbers
|
||||
result = complex_calculation(1, 2)
|
||||
# Step 1: 1+2=3, 2+2=4
|
||||
# Step 2: 3+4=7
|
||||
# Step 3: 7*10=70
|
||||
expected = 70
|
||||
assert result == expected, f"Expected {expected}, got {result}"
|
||||
|
||||
def test_complex_calculation_negative(self):
|
||||
"""Test multi-step calculation with negative numbers."""
|
||||
result = complex_calculation(-1, -2)
|
||||
# Step 1: -1+2=1, -2+2=0
|
||||
# Step 2: 1+0=1
|
||||
# Step 3: 1*10=10
|
||||
expected = 10
|
||||
assert result == expected, f"Expected {expected}, got {result}"
|
||||
|
||||
def test_add_numbers_basic(self):
|
||||
"""Test basic addition functionality."""
|
||||
assert add_numbers(2, 3) == 5
|
||||
assert add_numbers(10, 15) == 25
|
||||
assert add_numbers(0, 0) == 0
|
||||
|
||||
def test_add_numbers_negative(self):
|
||||
"""Test addition with negative numbers."""
|
||||
assert add_numbers(-5, 3) == -2
|
||||
assert add_numbers(-10, -15) == -25
|
||||
assert add_numbers(10, -5) == 5
|
||||
|
||||
def test_add_numbers_floats(self):
|
||||
"""Test addition with floating point numbers."""
|
||||
assert abs(add_numbers(2.5, 3.7) - 6.2) < 1e-9
|
||||
assert abs(add_numbers(1.1, 2.2) - 3.3) < 1e-9
|
||||
|
||||
|
||||
class TestSystemInfo:
|
||||
"""Test SystemInfo class."""
|
||||
|
||||
def test_system_info_creation(self):
|
||||
"""Test SystemInfo class instantiation."""
|
||||
info = SystemInfo()
|
||||
assert hasattr(info, 'python_version')
|
||||
assert hasattr(info, 'platform')
|
||||
assert hasattr(info, 'machine')
|
||||
|
||||
def test_system_info_properties(self):
|
||||
"""Test SystemInfo properties."""
|
||||
info = SystemInfo()
|
||||
|
||||
# Check python_version is a string
|
||||
assert isinstance(info.python_version, str)
|
||||
assert len(info.python_version) > 0
|
||||
|
||||
# Check platform is a string
|
||||
assert isinstance(info.platform, str)
|
||||
assert len(info.platform) > 0
|
||||
|
||||
# Check machine is a string
|
||||
assert isinstance(info.machine, str)
|
||||
assert len(info.machine) > 0
|
||||
|
||||
def test_system_info_str(self):
|
||||
"""Test SystemInfo string representation."""
|
||||
info = SystemInfo()
|
||||
str_repr = str(info)
|
||||
|
||||
assert isinstance(str_repr, str)
|
||||
assert "Python" in str_repr
|
||||
assert info.python_version in str_repr
|
||||
assert info.platform in str_repr
|
||||
assert info.machine in str_repr
|
||||
|
||||
def test_is_compatible(self):
|
||||
"""Test SystemInfo compatibility check."""
|
||||
info = SystemInfo()
|
||||
compatible = info.is_compatible()
|
||||
|
||||
# Should return a boolean
|
||||
assert isinstance(compatible, bool)
|
||||
|
||||
# Since we're running this test, Python should be >= 3.8
|
||||
assert compatible is True
|
||||
|
||||
|
||||
class TestDeveloperProfile:
|
||||
"""Test DeveloperProfile class."""
|
||||
|
||||
def test_developer_profile_creation_defaults(self):
|
||||
"""Test DeveloperProfile with default values."""
|
||||
profile = DeveloperProfile()
|
||||
|
||||
# Check default values
|
||||
assert profile.name == "Student"
|
||||
assert profile.email == "student@example.com"
|
||||
assert profile.affiliation == "TinyTorch Community"
|
||||
assert profile.specialization == "ML Systems"
|
||||
|
||||
def test_developer_profile_creation_custom(self):
|
||||
"""Test DeveloperProfile with custom values."""
|
||||
profile = DeveloperProfile(
|
||||
name="Test Student",
|
||||
email="test@example.com",
|
||||
affiliation="Test University",
|
||||
specialization="Deep Learning"
|
||||
)
|
||||
|
||||
assert profile.name == "Test Student"
|
||||
assert profile.email == "test@example.com"
|
||||
assert profile.affiliation == "Test University"
|
||||
assert profile.specialization == "Deep Learning"
|
||||
|
||||
def test_developer_profile_str(self):
|
||||
"""Test DeveloperProfile string representation."""
|
||||
profile = DeveloperProfile("Alice", "alice@example.com")
|
||||
str_repr = str(profile)
|
||||
|
||||
assert isinstance(str_repr, str)
|
||||
assert "Alice" in str_repr
|
||||
assert "alice@example.com" in str_repr
|
||||
|
||||
def test_developer_profile_signature(self):
|
||||
"""Test DeveloperProfile signature method."""
|
||||
profile = DeveloperProfile("Bob", "bob@example.com", "Test University", "Neural Networks")
|
||||
signature = profile.get_signature()
|
||||
|
||||
assert isinstance(signature, str)
|
||||
assert "Bob" in signature
|
||||
assert "Test University" in signature
|
||||
assert "Neural Networks" in signature
|
||||
|
||||
def test_developer_profile_info(self):
|
||||
"""Test DeveloperProfile get_profile_info method."""
|
||||
profile = DeveloperProfile("Charlie", "charlie@example.com", "AI Lab", "Computer Vision")
|
||||
info = profile.get_profile_info()
|
||||
|
||||
assert isinstance(info, dict)
|
||||
assert info['name'] == "Charlie"
|
||||
assert info['email'] == "charlie@example.com"
|
||||
assert info['affiliation'] == "AI Lab"
|
||||
assert info['specialization'] == "Computer Vision"
|
||||
|
||||
|
||||
class TestFileOperations:
|
||||
"""Test file-related operations."""
|
||||
|
||||
def test_hello_tinytorch_handles_missing_file(self, monkeypatch, capsys):
|
||||
"""Test that hello_tinytorch handles missing ASCII art file gracefully."""
|
||||
# Mock Path.exists to return False
|
||||
def mock_exists(self):
|
||||
return False
|
||||
|
||||
monkeypatch.setattr(Path, "exists", mock_exists)
|
||||
|
||||
# Should still work without the file
|
||||
hello_tinytorch()
|
||||
captured = capsys.readouterr()
|
||||
|
||||
# Should still print the branding text
|
||||
assert "TinyTorch" in captured.out
|
||||
assert "Build ML Systems from Scratch!" in captured.out
|
||||
|
||||
|
||||
class TestModuleIntegration:
|
||||
"""Test integration between different parts of the setup module."""
|
||||
|
||||
def test_all_functions_work_together(self):
|
||||
"""Test that all setup functions work without conflicts."""
|
||||
# Test functions
|
||||
hello_tinytorch() # Should not raise
|
||||
sum_result = add_numbers(5, 10)
|
||||
calc_result = complex_calculation(1, 1)
|
||||
|
||||
# Test classes
|
||||
info = SystemInfo()
|
||||
profile = DeveloperProfile()
|
||||
|
||||
# All should work without errors
|
||||
assert sum_result == 15
|
||||
assert calc_result == 60 # (1+2) + (1+2) = 6, 6*10 = 60
|
||||
assert str(info) # Should not be empty
|
||||
assert str(profile) # Should not be empty
|
||||
assert profile.get_signature() # Should not be empty
|
||||
|
||||
def test_no_import_errors(self):
|
||||
"""Test that imports work correctly."""
|
||||
# If we got here, imports worked
|
||||
assert callable(hello_tinytorch)
|
||||
assert callable(add_numbers)
|
||||
assert callable(complex_calculation)
|
||||
assert callable(SystemInfo)
|
||||
assert callable(DeveloperProfile)
|
||||
Reference in New Issue
Block a user