logisticspy 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 krishnanz550i-cmyk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.4
2
+ Name: logisticspy
3
+ Version: 0.1.0
4
+ Summary: A Python toolkit for logistics and supply chain calculations
5
+ Author: krishnanz550i-cmyk
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/krishnanz550i-cmyk/logisticspy
8
+ Project-URL: Issues, https://github.com/krishnanz550i-cmyk/logisticspy/issues
9
+ Keywords: logistics,supply chain,freight,chargeable weight
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Office/Business
15
+ Classifier: Topic :: Scientific/Engineering
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest; extra == "dev"
21
+ Dynamic: license-file
22
+
23
+ # logisticspy
24
+
25
+ A Python toolkit for logistics and supply chain calculations.
26
+
27
+ `logisticspy` is a growing collection of clean, well-tested tools for
28
+ common logistics and supply chain problems. The first module,
29
+ **`logisticspy.weight`**, calculates volumetric (dimensional) weight and
30
+ chargeable weight for air, courier, sea, road, and rail freight shipments.
31
+ More tools (volume, freight, inventory, and others) will be added over
32
+ time.
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ pip install logisticspy
38
+ ```
39
+
40
+ ## Quick start
41
+
42
+ You can use the chargeable weight tools either via the top-level package
43
+ or via the `weight` module:
44
+
45
+ ```python
46
+ # Option 1: top-level import
47
+ import logisticspy
48
+
49
+ result = logisticspy.calculate(
50
+ length=60, width=40, height=40, unit="cm",
51
+ actual_weight=18, weight_unit="kg",
52
+ mode="air",
53
+ )
54
+
55
+ # Option 2: import the weight module
56
+ from logisticspy.weight import chargeable_weight
57
+
58
+ result = chargeable_weight.calculate(
59
+ length=60, width=40, height=40, unit="cm",
60
+ actual_weight=18, weight_unit="kg",
61
+ mode="air",
62
+ )
63
+
64
+ print(result.volumetric_weight_kg) # 19.2
65
+ print(result.chargeable_weight_kg) # 19.2
66
+ print(result.basis) # "volumetric"
67
+ ```
68
+
69
+ ## The `weight` module: chargeable weight
70
+
71
+ Carriers bill shipments based on whichever is greater: the **actual
72
+ weight** or the **volumetric weight** (calculated from package
73
+ dimensions). This module implements that calculation cleanly, with
74
+ support for multiple units, transport modes, named divisor presets, and
75
+ multi-package consignments.
76
+
77
+ ### Supported modes and default divisors
78
+
79
+ | Mode | Default divisor (cm³/kg) |
80
+ |-----------|---------------------------|
81
+ | `air` | 6000 |
82
+ | `courier` | 5000 |
83
+ | `road` | 3000 |
84
+ | `rail` | 3000 |
85
+ | `sea` | N/A (uses CBM × 1000, see below) |
86
+
87
+ These are sensible starting defaults based on common conventions seen
88
+ across the freight and parcel industry. They are **not** tied to any
89
+ specific carrier - always confirm the applicable divisor with your own
90
+ carrier or contract for billing-critical calculations.
91
+
92
+ ### Divisor presets
93
+
94
+ Two divisor values - 5000 and 6000 - are both widely used across the
95
+ industry, often for different services, regions, or contracts (sometimes
96
+ even by the same carrier depending on the product). Rather than guessing
97
+ which one applies to your situation, you can refer to them by generic
98
+ preset labels and swap between them easily:
99
+
100
+ | Preset | Divisor |
101
+ |--------|---------|
102
+ | `"a"` | 5000 |
103
+ | `"b"` | 6000 |
104
+
105
+ ```python
106
+ import logisticspy
107
+
108
+ # Same package, two different divisor conventions
109
+ pkg = dict(length=60, width=40, height=40, actual_weight=10, mode="air")
110
+
111
+ result_a = logisticspy.calculate(**pkg, divisor_preset="a") # divisor 5000
112
+ result_b = logisticspy.calculate(**pkg, divisor_preset="b") # divisor 6000
113
+
114
+ print(result_a.volumetric_weight_kg) # 19.2
115
+ print(result_b.volumetric_weight_kg) # 16.0
116
+ ```
117
+
118
+ This makes it easy to compare "what would this shipment cost under each
119
+ convention" without hardcoding either value, and to plug in your own
120
+ carrier's documented divisor (whether that happens to be 5000, 6000, or
121
+ something else entirely) via `divisor_preset` or a raw `divisor=` value.
122
+
123
+ You can also pass an explicit divisor directly, which overrides any preset:
124
+
125
+ ```python
126
+ result = logisticspy.calculate(**pkg, divisor=4500)
127
+ ```
128
+
129
+ ### Units
130
+
131
+ #### Input units
132
+
133
+ Dimensions accept `cm`, `m`, `mm`, `in`, `ft` (default `cm`).
134
+ Weights accept `kg`, `g`, `lb`, `oz` (default `kg`).
135
+
136
+ ```python
137
+ result = logisticspy.calculate(
138
+ length=20, width=15, height=10, unit="in",
139
+ actual_weight=5, weight_unit="lb",
140
+ mode="courier",
141
+ )
142
+ ```
143
+
144
+ #### Output units (always normalized)
145
+
146
+ Regardless of the input units you choose, **all results are returned in
147
+ a single fixed unit system**:
148
+
149
+ | Field | Unit |
150
+ |-------|------|
151
+ | `actual_weight_kg`, `volumetric_weight_kg`, `chargeable_weight_kg` | kilograms (kg) |
152
+ | `volume_m3` | cubic meters (m³) |
153
+
154
+ The input units (`unit`, `weight_unit`) are only used to *interpret* the
155
+ numbers you pass in - they are converted to centimeters and kilograms
156
+ internally before any calculation happens. The output is never expressed
157
+ back in the input units.
158
+
159
+ If you need the result in a different unit (e.g. pounds), convert the
160
+ returned kg value yourself - the library does not provide unit conversion
161
+ on outputs.
162
+
163
+ ### Sea freight (CBM)
164
+
165
+ Sea freight chargeable weight is derived from volume in cubic meters
166
+ (CBM), using the common 1 CBM ≈ 1000 kg convention:
167
+
168
+ ```python
169
+ result = logisticspy.calculate(
170
+ length=1, width=1, height=1, unit="m",
171
+ actual_weight=500, mode="sea",
172
+ )
173
+ print(result.volumetric_weight_kg) # 1000.0
174
+ ```
175
+
176
+ Divisor presets are ignored for sea mode, since it uses a CBM-based
177
+ calculation rather than a divisor.
178
+
179
+ ### Multi-package consignments
180
+
181
+ ```python
182
+ import logisticspy
183
+
184
+ packages = [
185
+ {"length": 50, "width": 40, "height": 40, "actual_weight": 10},
186
+ {"length": 60, "width": 40, "height": 40, "actual_weight": 25, "quantity": 2},
187
+ ]
188
+
189
+ result = logisticspy.calculate_consignment(packages, mode="air")
190
+
191
+ print(result.total_actual_weight_kg)
192
+ print(result.total_volumetric_weight_kg)
193
+ print(result.total_chargeable_weight_kg)
194
+ ```
195
+
196
+ By default, totals are compared (`sum(actual)` vs `sum(volumetric)`).
197
+ Some couriers calculate chargeable weight per package and sum those - use
198
+ `per_piece=True` for that behavior:
199
+
200
+ ```python
201
+ result = logisticspy.calculate_consignment(packages, mode="air", per_piece=True)
202
+ ```
203
+
204
+ ## Roadmap
205
+
206
+ `logisticspy` is designed to grow into a broader logistics toolkit.
207
+ `chargeable_weight` is the first module; additional tools (e.g. volume,
208
+ freight, and inventory calculations) will be added over time.
209
+
210
+ ## Disclaimer
211
+
212
+ This library implements widely-used industry conventions for
213
+ illustrative and estimation purposes. Divisors and CBM ratios vary by
214
+ carrier, service level, region, and contract terms. Always confirm exact
215
+ billing methodology with your carrier or freight forwarder for
216
+ invoicing-critical calculations.
217
+
218
+ ## License
219
+
220
+ MIT
@@ -0,0 +1,198 @@
1
+ # logisticspy
2
+
3
+ A Python toolkit for logistics and supply chain calculations.
4
+
5
+ `logisticspy` is a growing collection of clean, well-tested tools for
6
+ common logistics and supply chain problems. The first module,
7
+ **`logisticspy.weight`**, calculates volumetric (dimensional) weight and
8
+ chargeable weight for air, courier, sea, road, and rail freight shipments.
9
+ More tools (volume, freight, inventory, and others) will be added over
10
+ time.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pip install logisticspy
16
+ ```
17
+
18
+ ## Quick start
19
+
20
+ You can use the chargeable weight tools either via the top-level package
21
+ or via the `weight` module:
22
+
23
+ ```python
24
+ # Option 1: top-level import
25
+ import logisticspy
26
+
27
+ result = logisticspy.calculate(
28
+ length=60, width=40, height=40, unit="cm",
29
+ actual_weight=18, weight_unit="kg",
30
+ mode="air",
31
+ )
32
+
33
+ # Option 2: import the weight module
34
+ from logisticspy.weight import chargeable_weight
35
+
36
+ result = chargeable_weight.calculate(
37
+ length=60, width=40, height=40, unit="cm",
38
+ actual_weight=18, weight_unit="kg",
39
+ mode="air",
40
+ )
41
+
42
+ print(result.volumetric_weight_kg) # 19.2
43
+ print(result.chargeable_weight_kg) # 19.2
44
+ print(result.basis) # "volumetric"
45
+ ```
46
+
47
+ ## The `weight` module: chargeable weight
48
+
49
+ Carriers bill shipments based on whichever is greater: the **actual
50
+ weight** or the **volumetric weight** (calculated from package
51
+ dimensions). This module implements that calculation cleanly, with
52
+ support for multiple units, transport modes, named divisor presets, and
53
+ multi-package consignments.
54
+
55
+ ### Supported modes and default divisors
56
+
57
+ | Mode | Default divisor (cm³/kg) |
58
+ |-----------|---------------------------|
59
+ | `air` | 6000 |
60
+ | `courier` | 5000 |
61
+ | `road` | 3000 |
62
+ | `rail` | 3000 |
63
+ | `sea` | N/A (uses CBM × 1000, see below) |
64
+
65
+ These are sensible starting defaults based on common conventions seen
66
+ across the freight and parcel industry. They are **not** tied to any
67
+ specific carrier - always confirm the applicable divisor with your own
68
+ carrier or contract for billing-critical calculations.
69
+
70
+ ### Divisor presets
71
+
72
+ Two divisor values - 5000 and 6000 - are both widely used across the
73
+ industry, often for different services, regions, or contracts (sometimes
74
+ even by the same carrier depending on the product). Rather than guessing
75
+ which one applies to your situation, you can refer to them by generic
76
+ preset labels and swap between them easily:
77
+
78
+ | Preset | Divisor |
79
+ |--------|---------|
80
+ | `"a"` | 5000 |
81
+ | `"b"` | 6000 |
82
+
83
+ ```python
84
+ import logisticspy
85
+
86
+ # Same package, two different divisor conventions
87
+ pkg = dict(length=60, width=40, height=40, actual_weight=10, mode="air")
88
+
89
+ result_a = logisticspy.calculate(**pkg, divisor_preset="a") # divisor 5000
90
+ result_b = logisticspy.calculate(**pkg, divisor_preset="b") # divisor 6000
91
+
92
+ print(result_a.volumetric_weight_kg) # 19.2
93
+ print(result_b.volumetric_weight_kg) # 16.0
94
+ ```
95
+
96
+ This makes it easy to compare "what would this shipment cost under each
97
+ convention" without hardcoding either value, and to plug in your own
98
+ carrier's documented divisor (whether that happens to be 5000, 6000, or
99
+ something else entirely) via `divisor_preset` or a raw `divisor=` value.
100
+
101
+ You can also pass an explicit divisor directly, which overrides any preset:
102
+
103
+ ```python
104
+ result = logisticspy.calculate(**pkg, divisor=4500)
105
+ ```
106
+
107
+ ### Units
108
+
109
+ #### Input units
110
+
111
+ Dimensions accept `cm`, `m`, `mm`, `in`, `ft` (default `cm`).
112
+ Weights accept `kg`, `g`, `lb`, `oz` (default `kg`).
113
+
114
+ ```python
115
+ result = logisticspy.calculate(
116
+ length=20, width=15, height=10, unit="in",
117
+ actual_weight=5, weight_unit="lb",
118
+ mode="courier",
119
+ )
120
+ ```
121
+
122
+ #### Output units (always normalized)
123
+
124
+ Regardless of the input units you choose, **all results are returned in
125
+ a single fixed unit system**:
126
+
127
+ | Field | Unit |
128
+ |-------|------|
129
+ | `actual_weight_kg`, `volumetric_weight_kg`, `chargeable_weight_kg` | kilograms (kg) |
130
+ | `volume_m3` | cubic meters (m³) |
131
+
132
+ The input units (`unit`, `weight_unit`) are only used to *interpret* the
133
+ numbers you pass in - they are converted to centimeters and kilograms
134
+ internally before any calculation happens. The output is never expressed
135
+ back in the input units.
136
+
137
+ If you need the result in a different unit (e.g. pounds), convert the
138
+ returned kg value yourself - the library does not provide unit conversion
139
+ on outputs.
140
+
141
+ ### Sea freight (CBM)
142
+
143
+ Sea freight chargeable weight is derived from volume in cubic meters
144
+ (CBM), using the common 1 CBM ≈ 1000 kg convention:
145
+
146
+ ```python
147
+ result = logisticspy.calculate(
148
+ length=1, width=1, height=1, unit="m",
149
+ actual_weight=500, mode="sea",
150
+ )
151
+ print(result.volumetric_weight_kg) # 1000.0
152
+ ```
153
+
154
+ Divisor presets are ignored for sea mode, since it uses a CBM-based
155
+ calculation rather than a divisor.
156
+
157
+ ### Multi-package consignments
158
+
159
+ ```python
160
+ import logisticspy
161
+
162
+ packages = [
163
+ {"length": 50, "width": 40, "height": 40, "actual_weight": 10},
164
+ {"length": 60, "width": 40, "height": 40, "actual_weight": 25, "quantity": 2},
165
+ ]
166
+
167
+ result = logisticspy.calculate_consignment(packages, mode="air")
168
+
169
+ print(result.total_actual_weight_kg)
170
+ print(result.total_volumetric_weight_kg)
171
+ print(result.total_chargeable_weight_kg)
172
+ ```
173
+
174
+ By default, totals are compared (`sum(actual)` vs `sum(volumetric)`).
175
+ Some couriers calculate chargeable weight per package and sum those - use
176
+ `per_piece=True` for that behavior:
177
+
178
+ ```python
179
+ result = logisticspy.calculate_consignment(packages, mode="air", per_piece=True)
180
+ ```
181
+
182
+ ## Roadmap
183
+
184
+ `logisticspy` is designed to grow into a broader logistics toolkit.
185
+ `chargeable_weight` is the first module; additional tools (e.g. volume,
186
+ freight, and inventory calculations) will be added over time.
187
+
188
+ ## Disclaimer
189
+
190
+ This library implements widely-used industry conventions for
191
+ illustrative and estimation purposes. Divisors and CBM ratios vary by
192
+ carrier, service level, region, and contract terms. Always confirm exact
193
+ billing methodology with your carrier or freight forwarder for
194
+ invoicing-critical calculations.
195
+
196
+ ## License
197
+
198
+ MIT
@@ -0,0 +1,43 @@
1
+ """
2
+ logisticspy: A Python toolkit for logistics and supply chain calculations.
3
+
4
+ The first module, ``logisticspy.weight``, calculates volumetric (dimensional)
5
+ and chargeable weight for air, courier, sea, road, and rail freight shipments.
6
+ More tools will be added over time.
7
+
8
+ Top-level convenience imports let you do either of:
9
+
10
+ import logisticspy
11
+ logisticspy.calculate(...)
12
+
13
+ from logisticspy.weight import chargeable_weight
14
+ chargeable_weight.calculate(...)
15
+ """
16
+
17
+ from .weight import (
18
+ calculate,
19
+ calculate_consignment,
20
+ WeightResult,
21
+ ConsolidatedResult,
22
+ Mode,
23
+ DEFAULT_DIVISORS,
24
+ DIVISOR_PRESETS,
25
+ UnsupportedUnitError,
26
+ UnsupportedModeError,
27
+ UnsupportedPresetError,
28
+ )
29
+
30
+ __version__ = "0.1.0"
31
+
32
+ __all__ = [
33
+ "calculate",
34
+ "calculate_consignment",
35
+ "WeightResult",
36
+ "ConsolidatedResult",
37
+ "Mode",
38
+ "DEFAULT_DIVISORS",
39
+ "DIVISOR_PRESETS",
40
+ "UnsupportedUnitError",
41
+ "UnsupportedModeError",
42
+ "UnsupportedPresetError",
43
+ ]
@@ -0,0 +1,28 @@
1
+ """
2
+ logisticspy.weight: Calculate volumetric (dimensional) and chargeable weight
3
+ for air, courier, sea, road, and rail freight shipments.
4
+ """
5
+
6
+ from .chargeable_weight import (
7
+ calculate,
8
+ calculate_consignment,
9
+ WeightResult,
10
+ ConsolidatedResult,
11
+ UnsupportedUnitError,
12
+ UnsupportedModeError,
13
+ UnsupportedPresetError,
14
+ )
15
+ from .divisors import Mode, DEFAULT_DIVISORS, DIVISOR_PRESETS
16
+
17
+ __all__ = [
18
+ "calculate",
19
+ "calculate_consignment",
20
+ "WeightResult",
21
+ "ConsolidatedResult",
22
+ "Mode",
23
+ "DEFAULT_DIVISORS",
24
+ "DIVISOR_PRESETS",
25
+ "UnsupportedUnitError",
26
+ "UnsupportedModeError",
27
+ "UnsupportedPresetError",
28
+ ]