bambon 1.0.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.
- bambon-1.0.0/PKG-INFO +204 -0
- bambon-1.0.0/README.md +189 -0
- bambon-1.0.0/pyproject.toml +26 -0
- bambon-1.0.0/setup.cfg +4 -0
- bambon-1.0.0/setup.py +17 -0
- bambon-1.0.0/src/bambon/__init__.py +0 -0
- bambon-1.0.0/src/bambon/distributions/__init__.py +0 -0
- bambon-1.0.0/src/bambon/distributions/belief.py +317 -0
- bambon-1.0.0/src/bambon/distributions/distributions.py +1031 -0
- bambon-1.0.0/src/bambon/models/__init__.py +0 -0
- bambon-1.0.0/src/bambon/models/expressions.py +33 -0
- bambon-1.0.0/src/bambon/models/models.py +72 -0
- bambon-1.0.0/src/bambon/negotiator.py +379 -0
- bambon-1.0.0/src/bambon/utils/__init__.py +0 -0
- bambon-1.0.0/src/bambon/utils/context.py +178 -0
- bambon-1.0.0/src/bambon/utils/distributions.py +87 -0
- bambon-1.0.0/src/bambon/utils/helpers.py +401 -0
- bambon-1.0.0/src/bambon.egg-info/PKG-INFO +204 -0
- bambon-1.0.0/src/bambon.egg-info/SOURCES.txt +41 -0
- bambon-1.0.0/src/bambon.egg-info/dependency_links.txt +1 -0
- bambon-1.0.0/src/bambon.egg-info/not-zip-safe +1 -0
- bambon-1.0.0/src/bambon.egg-info/requires.txt +1 -0
- bambon-1.0.0/src/bambon.egg-info/top_level.txt +2 -0
- bambon-1.0.0/src/bambonOld/__init__.py +0 -0
- bambon-1.0.0/src/bambonOld/distributions/__init__.py +0 -0
- bambon-1.0.0/src/bambonOld/distributions/belief.py +132 -0
- bambon-1.0.0/src/bambonOld/distributions/belief_old.py +176 -0
- bambon-1.0.0/src/bambonOld/distributions/distributions.py +148 -0
- bambon-1.0.0/src/bambonOld/distributions/distributions_old.py +154 -0
- bambon-1.0.0/src/bambonOld/models/__init__.py +0 -0
- bambon-1.0.0/src/bambonOld/models/expressions.py +27 -0
- bambon-1.0.0/src/bambonOld/models/models.py +22 -0
- bambon-1.0.0/src/bambonOld/negotiator.py +520 -0
- bambon-1.0.0/src/bambonOld/negotiator_old.py +594 -0
- bambon-1.0.0/src/bambonOld/utils/__init__.py +0 -0
- bambon-1.0.0/src/bambonOld/utils/agreement.py +68 -0
- bambon-1.0.0/src/bambonOld/utils/agreement_old.py +94 -0
- bambon-1.0.0/src/bambonOld/utils/hard_constraints.py +208 -0
- bambon-1.0.0/src/bambonOld/utils/hard_constraints_old.py +186 -0
- bambon-1.0.0/src/bambonOld/utils/helpers.py +173 -0
- bambon-1.0.0/src/bambonOld/utils/helpers_old.py +229 -0
- bambon-1.0.0/src/bambonOld/utils/semantics.py +141 -0
- bambon-1.0.0/tests/test_negotiator.py +262 -0
bambon-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bambon
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: An SDK to suppoort automated ODRL-policy negotiation.
|
|
5
|
+
Home-page: https://github.com/isotiropoulos/BayesianNegotiator
|
|
6
|
+
Author-email: Iason Sotiropoulos <isotiropoulos@singularlogic.eu>
|
|
7
|
+
Project-URL: Homepage, https://github.com/isotiropoulos/BayesianNegotiator
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: pydantic>=2.7.0
|
|
14
|
+
Dynamic: home-page
|
|
15
|
+
|
|
16
|
+
# Bambon Negotiator
|
|
17
|
+
|
|
18
|
+
**Bambon** (*Bayesian Adaptive Mixed-type Bilateral ODRL-policy Negotiator*) is a learning-based negotiator for **negotiating constraints over one or multiple actions** (e.g., `use`, `read`, `share`, `transfer`) expressed in an **ODRL-style policy format**.
|
|
19
|
+
|
|
20
|
+
Bambon observes opponent offers, updates Bayesian beliefs about opponent preferences (numeric / enum / set issues), and generates counter-offers until:
|
|
21
|
+
- agreement is reached (`odrl:Agreement`), or
|
|
22
|
+
- the negotiation becomes infeasible (`NegotiationInfeasible`)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
- ✅ Negotiates **constraints per action** (single-action or multi-action offers)
|
|
29
|
+
- ✅ Supports **mixed-type issues**:
|
|
30
|
+
- numeric constraints
|
|
31
|
+
- categorical/enum constraints
|
|
32
|
+
- set-valued constraints
|
|
33
|
+
- ✅ Bayesian belief models to learn opponent preferences over time
|
|
34
|
+
- ✅ Hard policy enforcement (non-negotiable constraints)
|
|
35
|
+
- ✅ Context similarity & severity scoring
|
|
36
|
+
- ✅ Hopelessness detection (fails fast if negotiation diverges)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Repository Structure
|
|
41
|
+
|
|
42
|
+
- `negotiator.py`
|
|
43
|
+
Main implementation: `Bambon` (observe / counter-offer / agreement logic)
|
|
44
|
+
|
|
45
|
+
- `belief.py`
|
|
46
|
+
`BeliefRegistry` manages belief models per action & issue
|
|
47
|
+
|
|
48
|
+
- `distributions.py`
|
|
49
|
+
Bayesian belief distributions:
|
|
50
|
+
- numeric beta-based model
|
|
51
|
+
- Dirichlet model for categorical constraints
|
|
52
|
+
- set belief handling
|
|
53
|
+
|
|
54
|
+
- `models.py`
|
|
55
|
+
Core dataclasses and `NegotiationInfeasible` exception
|
|
56
|
+
|
|
57
|
+
- `helpers.py`
|
|
58
|
+
Constraint parsing + operator helpers
|
|
59
|
+
|
|
60
|
+
- `context.py`
|
|
61
|
+
Similarity + severity scoring
|
|
62
|
+
|
|
63
|
+
- `expressions.py`
|
|
64
|
+
Expression helpers for constraints
|
|
65
|
+
|
|
66
|
+
- `test_negotiator.py`
|
|
67
|
+
Negotiation simulations / profiles (balanced, aggressive, exploratory)
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Offer Format (ODRL-style)
|
|
72
|
+
|
|
73
|
+
Bambon expects offers in an ODRL-like JSON format:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"@id": "urn:uid:example",
|
|
78
|
+
"@type": "odrl:Offer",
|
|
79
|
+
"permission": [
|
|
80
|
+
{
|
|
81
|
+
"action": "use",
|
|
82
|
+
"constraint": [
|
|
83
|
+
{
|
|
84
|
+
"leftOperand": "odrl:purpose",
|
|
85
|
+
"operator": "odrl:eq",
|
|
86
|
+
"rightOperand": "research"
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Constraints are normalized internally (e.g., `odrl:` prefixes stripped during parsing).
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Quickstart
|
|
99
|
+
|
|
100
|
+
### 1) Create a negotiator
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from negotiator import Bambon
|
|
104
|
+
|
|
105
|
+
neg = Bambon(
|
|
106
|
+
name="Provider",
|
|
107
|
+
init_offer=init_offer, # required
|
|
108
|
+
hard_policy=hard_policy # optional
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Each action in `init_offer["permission"]` gets its own:
|
|
113
|
+
- belief registry
|
|
114
|
+
- negotiation state
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### 2) Observe an opponent offer and generate a response
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
signals, response_offer = neg.observe(opponent_offer)
|
|
122
|
+
|
|
123
|
+
print("Signals:", signals)
|
|
124
|
+
print("Response:", response_offer)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- `signals` is `None` while negotiating
|
|
128
|
+
- `signals` becomes non-null when an action is accepted and agreement is formed
|
|
129
|
+
- `response_offer` will be either:
|
|
130
|
+
- a counter-offer (`odrl:Offer`), or
|
|
131
|
+
- an agreement (`odrl:Agreement`)
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Running
|
|
136
|
+
|
|
137
|
+
### Run tests (recommended)
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
pytest -q
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
or:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
python -m unittest -v
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Example Minimal Negotiation Loop
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from negotiator import Bambon
|
|
155
|
+
|
|
156
|
+
provider = Bambon(name="Provider", init_offer=provider_init, hard_policy=provider_hard)
|
|
157
|
+
consumer = Bambon(name="Consumer", init_offer=consumer_init)
|
|
158
|
+
|
|
159
|
+
offer = consumer_init
|
|
160
|
+
for round_i in range(50):
|
|
161
|
+
sig_p, offer = provider.observe(offer)
|
|
162
|
+
if offer.get("@type") == "odrl:Agreement":
|
|
163
|
+
print("Agreement reached (provider -> consumer)")
|
|
164
|
+
break
|
|
165
|
+
|
|
166
|
+
sig_c, offer = consumer.observe(offer)
|
|
167
|
+
if offer.get("@type") == "odrl:Agreement":
|
|
168
|
+
print("Agreement reached (consumer -> provider)")
|
|
169
|
+
break
|
|
170
|
+
else:
|
|
171
|
+
print("No agreement reached within max rounds")
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Key Negotiation Parameters
|
|
177
|
+
|
|
178
|
+
Bambon behavior is governed by tunable controls, including:
|
|
179
|
+
|
|
180
|
+
- `lr` — learning rate for belief updates
|
|
181
|
+
- `inertia` — resistance to changing past proposals
|
|
182
|
+
- `tau_in`, `tau_out` — thresholds controlling adaptation vs acceptance
|
|
183
|
+
- `max_set_k` — maximum size for proposed sets
|
|
184
|
+
- `jaccard_snap_threshold` — snaps set proposals when overlap is high
|
|
185
|
+
- `no_agreement_until` — prevents early agreement before minimum rounds
|
|
186
|
+
- `max_rounds` — maximum rounds before infeasibility
|
|
187
|
+
- `hopeless_window`, `hopeless_patience` — detects non-converging negotiation
|
|
188
|
+
|
|
189
|
+
If negotiation is judged impossible, Bambon raises:
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from models import NegotiationInfeasible
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Output Types
|
|
198
|
+
|
|
199
|
+
Bambon produces ODRL-like structures:
|
|
200
|
+
|
|
201
|
+
- **Counter-offer**: `@type = "odrl:Offer"`
|
|
202
|
+
- **Agreement**: `@type = "odrl:Agreement"` with constraints filled using accepted values
|
|
203
|
+
|
|
204
|
+
---
|
bambon-1.0.0/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Bambon Negotiator
|
|
2
|
+
|
|
3
|
+
**Bambon** (*Bayesian Adaptive Mixed-type Bilateral ODRL-policy Negotiator*) is a learning-based negotiator for **negotiating constraints over one or multiple actions** (e.g., `use`, `read`, `share`, `transfer`) expressed in an **ODRL-style policy format**.
|
|
4
|
+
|
|
5
|
+
Bambon observes opponent offers, updates Bayesian beliefs about opponent preferences (numeric / enum / set issues), and generates counter-offers until:
|
|
6
|
+
- agreement is reached (`odrl:Agreement`), or
|
|
7
|
+
- the negotiation becomes infeasible (`NegotiationInfeasible`)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- ✅ Negotiates **constraints per action** (single-action or multi-action offers)
|
|
14
|
+
- ✅ Supports **mixed-type issues**:
|
|
15
|
+
- numeric constraints
|
|
16
|
+
- categorical/enum constraints
|
|
17
|
+
- set-valued constraints
|
|
18
|
+
- ✅ Bayesian belief models to learn opponent preferences over time
|
|
19
|
+
- ✅ Hard policy enforcement (non-negotiable constraints)
|
|
20
|
+
- ✅ Context similarity & severity scoring
|
|
21
|
+
- ✅ Hopelessness detection (fails fast if negotiation diverges)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Repository Structure
|
|
26
|
+
|
|
27
|
+
- `negotiator.py`
|
|
28
|
+
Main implementation: `Bambon` (observe / counter-offer / agreement logic)
|
|
29
|
+
|
|
30
|
+
- `belief.py`
|
|
31
|
+
`BeliefRegistry` manages belief models per action & issue
|
|
32
|
+
|
|
33
|
+
- `distributions.py`
|
|
34
|
+
Bayesian belief distributions:
|
|
35
|
+
- numeric beta-based model
|
|
36
|
+
- Dirichlet model for categorical constraints
|
|
37
|
+
- set belief handling
|
|
38
|
+
|
|
39
|
+
- `models.py`
|
|
40
|
+
Core dataclasses and `NegotiationInfeasible` exception
|
|
41
|
+
|
|
42
|
+
- `helpers.py`
|
|
43
|
+
Constraint parsing + operator helpers
|
|
44
|
+
|
|
45
|
+
- `context.py`
|
|
46
|
+
Similarity + severity scoring
|
|
47
|
+
|
|
48
|
+
- `expressions.py`
|
|
49
|
+
Expression helpers for constraints
|
|
50
|
+
|
|
51
|
+
- `test_negotiator.py`
|
|
52
|
+
Negotiation simulations / profiles (balanced, aggressive, exploratory)
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Offer Format (ODRL-style)
|
|
57
|
+
|
|
58
|
+
Bambon expects offers in an ODRL-like JSON format:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"@id": "urn:uid:example",
|
|
63
|
+
"@type": "odrl:Offer",
|
|
64
|
+
"permission": [
|
|
65
|
+
{
|
|
66
|
+
"action": "use",
|
|
67
|
+
"constraint": [
|
|
68
|
+
{
|
|
69
|
+
"leftOperand": "odrl:purpose",
|
|
70
|
+
"operator": "odrl:eq",
|
|
71
|
+
"rightOperand": "research"
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Constraints are normalized internally (e.g., `odrl:` prefixes stripped during parsing).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Quickstart
|
|
84
|
+
|
|
85
|
+
### 1) Create a negotiator
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from negotiator import Bambon
|
|
89
|
+
|
|
90
|
+
neg = Bambon(
|
|
91
|
+
name="Provider",
|
|
92
|
+
init_offer=init_offer, # required
|
|
93
|
+
hard_policy=hard_policy # optional
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Each action in `init_offer["permission"]` gets its own:
|
|
98
|
+
- belief registry
|
|
99
|
+
- negotiation state
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### 2) Observe an opponent offer and generate a response
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
signals, response_offer = neg.observe(opponent_offer)
|
|
107
|
+
|
|
108
|
+
print("Signals:", signals)
|
|
109
|
+
print("Response:", response_offer)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- `signals` is `None` while negotiating
|
|
113
|
+
- `signals` becomes non-null when an action is accepted and agreement is formed
|
|
114
|
+
- `response_offer` will be either:
|
|
115
|
+
- a counter-offer (`odrl:Offer`), or
|
|
116
|
+
- an agreement (`odrl:Agreement`)
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Running
|
|
121
|
+
|
|
122
|
+
### Run tests (recommended)
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pytest -q
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
or:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
python -m unittest -v
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Example Minimal Negotiation Loop
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from negotiator import Bambon
|
|
140
|
+
|
|
141
|
+
provider = Bambon(name="Provider", init_offer=provider_init, hard_policy=provider_hard)
|
|
142
|
+
consumer = Bambon(name="Consumer", init_offer=consumer_init)
|
|
143
|
+
|
|
144
|
+
offer = consumer_init
|
|
145
|
+
for round_i in range(50):
|
|
146
|
+
sig_p, offer = provider.observe(offer)
|
|
147
|
+
if offer.get("@type") == "odrl:Agreement":
|
|
148
|
+
print("Agreement reached (provider -> consumer)")
|
|
149
|
+
break
|
|
150
|
+
|
|
151
|
+
sig_c, offer = consumer.observe(offer)
|
|
152
|
+
if offer.get("@type") == "odrl:Agreement":
|
|
153
|
+
print("Agreement reached (consumer -> provider)")
|
|
154
|
+
break
|
|
155
|
+
else:
|
|
156
|
+
print("No agreement reached within max rounds")
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Key Negotiation Parameters
|
|
162
|
+
|
|
163
|
+
Bambon behavior is governed by tunable controls, including:
|
|
164
|
+
|
|
165
|
+
- `lr` — learning rate for belief updates
|
|
166
|
+
- `inertia` — resistance to changing past proposals
|
|
167
|
+
- `tau_in`, `tau_out` — thresholds controlling adaptation vs acceptance
|
|
168
|
+
- `max_set_k` — maximum size for proposed sets
|
|
169
|
+
- `jaccard_snap_threshold` — snaps set proposals when overlap is high
|
|
170
|
+
- `no_agreement_until` — prevents early agreement before minimum rounds
|
|
171
|
+
- `max_rounds` — maximum rounds before infeasibility
|
|
172
|
+
- `hopeless_window`, `hopeless_patience` — detects non-converging negotiation
|
|
173
|
+
|
|
174
|
+
If negotiation is judged impossible, Bambon raises:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from models import NegotiationInfeasible
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Output Types
|
|
183
|
+
|
|
184
|
+
Bambon produces ODRL-like structures:
|
|
185
|
+
|
|
186
|
+
- **Counter-offer**: `@type = "odrl:Offer"`
|
|
187
|
+
- **Agreement**: `@type = "odrl:Agreement"` with constraints filled using accepted values
|
|
188
|
+
|
|
189
|
+
---
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "bambon"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Iason Sotiropoulos", email="isotiropoulos@singularlogic.eu"},
|
|
10
|
+
]
|
|
11
|
+
dependencies = [
|
|
12
|
+
"pydantic>=2.7.0"
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
description = "An SDK to suppoort automated ODRL-policy negotiation."
|
|
16
|
+
readme = "README.md"
|
|
17
|
+
requires-python = ">=3.8"
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
]
|
|
23
|
+
#
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://github.com/isotiropoulos/BayesianNegotiator"
|
|
26
|
+
#Issues = "https://github.com/pypa/sampleproject/issues"
|
bambon-1.0.0/setup.cfg
ADDED
bambon-1.0.0/setup.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
from os import path
|
|
3
|
+
|
|
4
|
+
working_directory = path.abspath(path.dirname(__file__))
|
|
5
|
+
|
|
6
|
+
with open(path.join(working_directory, 'README.md'), encoding='utf-8') as f:
|
|
7
|
+
long_description = f.read()
|
|
8
|
+
|
|
9
|
+
setup(
|
|
10
|
+
name='bambon', # name of packe which will be package dir below project
|
|
11
|
+
url='https://github.com/isotiropoulos/BayesianNegotiator',
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type='text/markdown',
|
|
14
|
+
packages=find_packages('src'),
|
|
15
|
+
package_dir={'': 'src'},
|
|
16
|
+
zip_safe=False
|
|
17
|
+
)
|
|
File without changes
|
|
File without changes
|