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
Metadata
Release files for dimcalc 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dimcalc-1.0.0.tar.gz | 12.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dimcalc-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.3 kB
Release files / dimcalc-1.0.0.tar.gz
| Download URL | dimcalc-1.0.0.tar.gz |
|---|---|
| Size | 12.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
98b23afa611186208811c46180f0fe55f336333757ff198a7273d9578a5fa584
|
|
BLAKE2b-256 checksum How to use checksums |
5c30adad28737c533ab76ffc681e693ae69cc25d0b5539a739888508862ecc4b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / dimcalc-1.0.0-py3-none-any.whl
| Download URL | dimcalc-1.0.0-py3-none-any.whl |
|---|---|
| Size | 11.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3b510478ba23e05aea5c3a8d78a7647b3d43787ebe316b454f4c50447af3c04b
|
|
BLAKE2b-256 checksum How to use checksums |
02e7facd17859fc2a7302dee6c30d841d007bb952c7811cd73b6a774a5285e84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|