Dimensional weight calculator and box selector for shipping
Project description
dimcalc
A Python library for calculating dimensional (volumetric) weight and selecting optimal shipping boxes.
Features
- Calculate dimensional weight using configurable DIM factors
- Select optimal shipping boxes from a list of available sizes
- Distribute chargeable weight proportionally across products
- Built with Pydantic for data validation
- Type hints throughout for IDE support
Installation
pip install dimcalc
Quick Start
Basic Dimensional Weight Calculation
from dimcalc import DimCalc, Dimensions
# Create a calculator with your carrier's DIM factor
calc = DimCalc(dimensional_factor=5.0) # 5.0 for cm³ to grams
# Define product dimensions (in centimeters)
dims = Dimensions(length=30, width=20, height=10)
# Calculate chargeable weight
result = calc.calculate_chargeable_weight(
actual_weight=500, # grams
dimensions=dims,
quantity=2
)
print(f"Actual weight: {result.actual_weight}g")
print(f"Dimensional weight: {result.dimensional_weight}g")
print(f"Chargeable weight: {result.chargeable_weight}g")
print(f"Using dimensional: {result.is_dimensional_used}")
Box Selection
from dimcalc import BoxSelector, Box, Product, Dimensions
# Define your available box sizes
boxes = [
Box(id="small", length=20, width=15, height=10, name="Small"),
Box(id="medium", length=30, width=25, height=15, name="Medium"),
Box(id="large", length=40, width=30, height=20, name="Large"),
]
# Create a selector with 20% volume buffer for packing inefficiency
selector = BoxSelector(boxes=boxes, volume_buffer_percentage=20.0)
# Define products to ship
products = [
Product(
weight=500, # grams per unit
quantity=2,
dimensions=Dimensions(length=15, width=10, height=8)
),
Product(
weight=300,
quantity=1,
dimensions=Dimensions(length=10, width=10, height=5)
),
]
# Select optimal box
result = selector.select_box(products)
print(f"Selected box: {result.box.name}")
print(f"Chargeable weight: {result.weight.chargeable_weight}g")
print(f"Box utilization: {result.utilization_percentage:.1f}%")
Weight Distribution
When using box-based calculation, distribute the chargeable weight back to individual products:
from dimcalc import WeightDistributor
# After box selection...
distributed = WeightDistributor.distribute(products, result)
for i, dist in enumerate(distributed):
print(f"Product {i+1}: {dist.distributed_weight}g per unit")
API Reference
Models
Dimensions
Represents physical dimensions in centimeters.
dims = Dimensions(length=30, width=20, height=10)
dims.volume # 6000.0 (cm³)
dims.max_dimension # 30.0
Box
Represents a shipping box.
box = Box(
id="box_1", # Unique identifier
length=30, # cm
width=20, # cm
height=10, # cm
name="Medium Box" # Optional display name
)
box.volume # 6000.0 (cm³)
box.max_dimension # 30.0
box.dimensions # Returns Dimensions object
Product
Represents a product for weight/box calculation.
product = Product(
weight=500, # grams per unit
quantity=2, # number of units (default: 1)
dimensions=Dimensions(...) # optional dimensions
)
product.total_weight # 1000 (weight × quantity)
product.total_volume # volume × quantity (or None if no dimensions)
WeightResult
Result of a dimensional weight calculation.
result.actual_weight # Total actual weight in grams
result.dimensional_weight # Calculated dimensional weight
result.chargeable_weight # max(actual, dimensional)
result.is_dimensional_used # True if dimensional > actual
result.weight_difference # chargeable - actual
BoxSelectionResult
Result of box selection with weight calculation.
result.box # Selected Box
result.weight # WeightResult
result.total_products_volume # Sum of product volumes
result.utilization_percentage # (products_volume / box_volume) × 100
result.to_dict() # Convert to dictionary for JSON
Classes
DimCalc
Core dimensional weight calculator.
calc = DimCalc(dimensional_factor=5.0)
# Calculate dimensional weight only
dim_weight = calc.calculate_dimensional_weight(dimensions, quantity=1)
# Calculate chargeable weight (max of actual and dimensional)
result = calc.calculate_chargeable_weight(
actual_weight=500,
dimensions=dims,
quantity=1
)
# Calculate for multiple products
result = calc.calculate_for_products(products)
BoxSelector
Selects optimal shipping box for products.
selector = BoxSelector(
boxes=boxes, # List of available Box objects
volume_buffer_percentage=20.0, # Extra space for packing (default: 20%)
calculator=DimCalc() # Optional custom calculator
)
result = selector.select_box(products) # Returns BoxSelectionResult or None
can_fit = selector.can_fit(products) # Returns bool
WeightDistributor
Distributes chargeable weight across products.
# Proportional distribution (based on actual weight)
distributed = WeightDistributor.distribute(products, box_result)
# Even distribution (equal per unit)
distributed = WeightDistributor.distribute_evenly(products, total_weight)
Dimensional Factors
The dimensional factor (DIM factor) converts volume to weight. Common values:
| Carrier | Factor | Unit Conversion |
|---|---|---|
| Iran Post | 5.0 | cm³ → grams |
| DHL | 5000.0 | cm³ → kg |
Formula: dimensional_weight = volume / dimensional_factor
Presets
The library includes example presets you can use as reference:
from dimcalc.presets import IRAN_POST_BOXES, DIMENSIONAL_FACTORS, get_iran_post_selector
# Example box configurations
print(IRAN_POST_BOXES) # List of 8 standard Iran Post boxes
# Common DIM factors
print(DIMENSIONAL_FACTORS) # {"iran_post": 5.0, "dhl": 5000.0, ...}
# Pre-configured selector for Iran Post
selector = get_iran_post_selector()
Note: Box sizes vary by region and carrier. Create your own box list based on your specific requirements:
# Define your own boxes
MY_BOXES = [
Box(id="xs", length=15, width=10, height=10, name="Extra Small"),
Box(id="s", length=20, width=15, height=10, name="Small"),
Box(id="m", length=30, width=20, height=15, name="Medium"),
Box(id="l", length=40, width=30, height=20, name="Large"),
]
selector = BoxSelector(boxes=MY_BOXES)
JSON Serialization
Results can be easily serialized for API responses:
result = selector.select_box(products)
data = result.to_dict()
# Returns:
{
"box_id": "medium",
"box_name": "Medium Box",
"box_dimensions": {
"length_cm": 30,
"width_cm": 20,
"height_cm": 15,
"volume_cm3": 9000
},
"weight": {
"actual_weight_g": 1300,
"dimensional_weight_g": 1800,
"chargeable_weight_g": 1800,
"is_dimensional_used": True
},
"packing_info": {
"total_products_volume_cm3": 2900,
"utilization_percentage": 32.22
}
}
Pydantic models also support .model_dump() for serialization:
dims = Dimensions(length=30, width=20, height=10)
dims.model_dump() # {"length": 30, "width": 20, "height": 10, "volume": 6000, "max_dimension": 30}
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dimcalc-1.0.0.tar.gz.
File metadata
- Download URL: dimcalc-1.0.0.tar.gz
- Upload date:
- Size: 12.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98b23afa611186208811c46180f0fe55f336333757ff198a7273d9578a5fa584
|
|
| MD5 |
b482bdf4feae1d3731c862614f858912
|
|
| BLAKE2b-256 |
5c30adad28737c533ab76ffc681e693ae69cc25d0b5539a739888508862ecc4b
|
File details
Details for the file dimcalc-1.0.0-py3-none-any.whl.
File metadata
- Download URL: dimcalc-1.0.0-py3-none-any.whl
- Upload date:
- Size: 11.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b510478ba23e05aea5c3a8d78a7647b3d43787ebe316b454f4c50447af3c04b
|
|
| MD5 |
4c3cef8f7613f4fa99915e93b98433c0
|
|
| BLAKE2b-256 |
02e7facd17859fc2a7302dee6c30d841d007bb952c7811cd73b6a774a5285e84
|