anson.py3 0.1.0__py3-none-any.whl
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.
- anson/__init__.py +0 -0
- anson/io/odysz/__init__.py +0 -0
- anson/io/odysz/anson/__init__.py +0 -0
- anson/io/odysz/anson/x/__init__.py +10 -0
- anson/io/odysz/ansons.py +231 -0
- anson/io/odysz/common.py +83 -0
- anson_py3-0.1.0.dist-info/METADATA +181 -0
- anson_py3-0.1.0.dist-info/RECORD +10 -0
- anson_py3-0.1.0.dist-info/WHEEL +4 -0
- anson_py3-0.1.0.dist-info/licenses/LICENSE +21 -0
anson/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
|
|
2
|
+
class AnsonException:
|
|
3
|
+
type = "io.odysz.ansons.x.AnsonException"
|
|
4
|
+
excode = 0
|
|
5
|
+
err = ""
|
|
6
|
+
|
|
7
|
+
def __init__(self, excode: int, template: str, *param: object):
|
|
8
|
+
super().__init__()
|
|
9
|
+
self.excode = excode
|
|
10
|
+
self.err = template if param is None else template.format(param)
|
anson/io/odysz/ansons.py
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import sys
|
|
3
|
+
from dataclasses import dataclass, fields, MISSING, Field
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from numbers import Number
|
|
7
|
+
from typing import TypeVar, List, Dict, get_origin, get_args, ForwardRef, Type, Any, Union, Optional
|
|
8
|
+
|
|
9
|
+
from .common import Utils
|
|
10
|
+
|
|
11
|
+
TAnson = TypeVar('TAnson', bound='Anson')
|
|
12
|
+
|
|
13
|
+
java_src_path: str = ''
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class Anson(dict):
|
|
17
|
+
enclosinguardtypes = set()
|
|
18
|
+
|
|
19
|
+
__type__: str
|
|
20
|
+
'''ansons.antson.Anson'''
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
super().__init__()
|
|
24
|
+
t = type(self)
|
|
25
|
+
self.__type__ = f'{t.__module__}.{t.__name__}'
|
|
26
|
+
|
|
27
|
+
def __setitem__(self, key, value):
|
|
28
|
+
self.__dict__[key] = value
|
|
29
|
+
|
|
30
|
+
def __getitem__(self, key):
|
|
31
|
+
return self.__dict__[key]
|
|
32
|
+
|
|
33
|
+
@dataclass()
|
|
34
|
+
class Trumpfield():
|
|
35
|
+
'''
|
|
36
|
+
{name, type, isAnson, antype, factory}
|
|
37
|
+
'''
|
|
38
|
+
name: str
|
|
39
|
+
fieldtype: type
|
|
40
|
+
origintype: type
|
|
41
|
+
isAnson: bool
|
|
42
|
+
elemtype: type
|
|
43
|
+
antype: str
|
|
44
|
+
factory: any
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def fields(instance) -> dict[str, Trumpfield]:
|
|
48
|
+
_FIELDS = '__dataclass_fields__' # see dataclasses.fields()
|
|
49
|
+
fds = getattr(type(instance), _FIELDS)
|
|
50
|
+
|
|
51
|
+
def get_mandatype(t: TypeVar):
|
|
52
|
+
if isinstance(t, type(Optional[Any])):
|
|
53
|
+
return get_args(t)[0]
|
|
54
|
+
elif sys.version_info > (3,10,0) and isinstance(t, type(Any | None)):
|
|
55
|
+
print(get_args(t))
|
|
56
|
+
for m in get_args(t):
|
|
57
|
+
if m is not type(None):
|
|
58
|
+
return m
|
|
59
|
+
return t
|
|
60
|
+
|
|
61
|
+
def figureNormalType(f: Field) -> tuple:
|
|
62
|
+
try: isAnson = issubclass(f.type, Anson) or isinstance(f.type, Anson)
|
|
63
|
+
except: isAnson = False
|
|
64
|
+
return f, get_origin(f.type), get_args(f.type), isAnson
|
|
65
|
+
|
|
66
|
+
def figure_list(f: Field, guardTypes: set[Anson]):
|
|
67
|
+
if not isinstance(f.type, list):
|
|
68
|
+
raise Exception("Not here")
|
|
69
|
+
|
|
70
|
+
ot = list
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
et = f.type[0].__bound__ if len(f.type[0]) > 0 and isinstance(f.type[0], TypeVar) else get_args(f.type)
|
|
74
|
+
et = et.__evaluate(globals(), locals(), recursive_guard=guardTypes) if isinstance(et, ForwardRef) else et
|
|
75
|
+
et = (et)
|
|
76
|
+
except: et = ()
|
|
77
|
+
return f, ot, et, False
|
|
78
|
+
|
|
79
|
+
def figure_dict(f: Field, envType: set[Anson]) -> tuple:
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
def toTrump(fn: Field):
|
|
83
|
+
"""
|
|
84
|
+
Simply & brutally figuring types. We only care about Anson types, the exceptional.
|
|
85
|
+
:param fn:
|
|
86
|
+
:return: TrumpField
|
|
87
|
+
"""
|
|
88
|
+
f = fds[fn]
|
|
89
|
+
f.type = get_mandatype(f.type)
|
|
90
|
+
|
|
91
|
+
if isinstance(f.type, List):
|
|
92
|
+
f, ot, et, isAnson = figure_list(f, Anson.enclosinguardtypes)
|
|
93
|
+
elif isinstance(f.type, Dict):
|
|
94
|
+
f, ot, et, isAnson = figure_dict(f, Anson.enclosinguardtypes)
|
|
95
|
+
else:
|
|
96
|
+
f, ot, et, isAnson = figureNormalType(f)
|
|
97
|
+
|
|
98
|
+
return Anson.Trumpfield(
|
|
99
|
+
f.name, f.type,
|
|
100
|
+
ot, isAnson,
|
|
101
|
+
None if et is None or len(et) == 0 else et[0],
|
|
102
|
+
'str' if f.type == str else
|
|
103
|
+
'lst' if ot == list else
|
|
104
|
+
'dic' if ot == dict else
|
|
105
|
+
'num' if ot is None and issubclass(f.type, Number) else
|
|
106
|
+
f.type if isAnson else
|
|
107
|
+
'obj',
|
|
108
|
+
None if f.default_factory is MISSING else f.default_factory)
|
|
109
|
+
|
|
110
|
+
return {it: toTrump(it) for it in fds}
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def toList_(lst: list, elemtype: type, ind: int):
|
|
114
|
+
if elemtype is None or not issubclass(elemtype, Anson): return str(lst)
|
|
115
|
+
return '[\n' + ','.join([Anson.toBlock_(e, ind + 1) for e in lst]) + ']'
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def toDict_(dic: dict, elemtype: type, ind: int):
|
|
119
|
+
if elemtype is None or not issubclass(elemtype, Anson): return json.dumps(dic)
|
|
120
|
+
return '{\n' + ',\n'.join(' ' * (ind * 2 + 2) + Anson.toBlock_(dic[k], ind + 1) for k in dic) + ']'
|
|
121
|
+
|
|
122
|
+
def toBlock(self) -> str:
|
|
123
|
+
return self.toBlock_(0)
|
|
124
|
+
|
|
125
|
+
def toFile(self, path: str):
|
|
126
|
+
with open(path, 'w+') as jf:
|
|
127
|
+
jf.write(self.toBlock())
|
|
128
|
+
|
|
129
|
+
def toBlock_(self, ind: int) -> str:
|
|
130
|
+
myfds = self.fields(self)
|
|
131
|
+
s = ' ' * (ind * 2) + '{\n'
|
|
132
|
+
# incorrect if there is a ignored: lx = len(self.__dict__) - 1
|
|
133
|
+
has_prvious = False
|
|
134
|
+
for x, k in enumerate(self.__dict__):
|
|
135
|
+
if '__type__' == k:
|
|
136
|
+
if ind == 0:
|
|
137
|
+
tp = str(self['__type__']).removeprefix(java_src_path+'.')
|
|
138
|
+
if has_prvious: s += ',\n'
|
|
139
|
+
s += f' "type": "{tp}"'
|
|
140
|
+
has_prvious = True
|
|
141
|
+
else: continue # later can figure out type by field's type
|
|
142
|
+
else:
|
|
143
|
+
if k not in myfds:
|
|
144
|
+
Utils.warn("Field {0}.{1} is not defined in Anson, which is presenting in data object. Value ignored: {1}.",
|
|
145
|
+
str(self['__type__']), k, self[k])
|
|
146
|
+
continue
|
|
147
|
+
if has_prvious: s += ',\n'
|
|
148
|
+
s += f'{" " * (ind * 2 + 2)}"{k}": '
|
|
149
|
+
v = self[k]
|
|
150
|
+
s += 'null' if v is None or isinstance(v, Field) \
|
|
151
|
+
else f'"{v}"' if isinstance(v, str) \
|
|
152
|
+
else v.toBlock_(ind + 1) if myfds[k].isAnson \
|
|
153
|
+
else Anson.toList_(v, myfds[k].elemtype, ind + 1) if myfds[k].antype == 'lst' \
|
|
154
|
+
else Anson.toDict_(v, myfds[k].elemtype, ind + 1) if myfds[k].antype == 'obj' \
|
|
155
|
+
else str(v)
|
|
156
|
+
|
|
157
|
+
has_prvious = True
|
|
158
|
+
# s += ',\n' if x != lx else '\n'
|
|
159
|
+
return s + ('\n' if has_prvious else '') + ' ' * (ind * 2) + '}'
|
|
160
|
+
|
|
161
|
+
@staticmethod
|
|
162
|
+
def from_dict(v: dict, eletype: type) -> dict:
|
|
163
|
+
if eletype is None: return v
|
|
164
|
+
|
|
165
|
+
d = {}
|
|
166
|
+
for k in v:
|
|
167
|
+
d[k] = Anson.from_obj(v[k], eletype)
|
|
168
|
+
return d
|
|
169
|
+
|
|
170
|
+
@staticmethod
|
|
171
|
+
def from_list(v: list, eletype: type) -> list:
|
|
172
|
+
if eletype is None: return v
|
|
173
|
+
return [Anson.from_obj(x, eletype) for x in v]
|
|
174
|
+
|
|
175
|
+
@staticmethod
|
|
176
|
+
def from_obj(obj: dict, typename: Union[str, type]) -> TAnson:
|
|
177
|
+
def getClass(_typ_: str):
|
|
178
|
+
parts = _typ_.split('.')
|
|
179
|
+
# if len(java_src_path) > 0:
|
|
180
|
+
# parts.insert(0, java_src_path)
|
|
181
|
+
module = ".".join(parts[:-1])
|
|
182
|
+
m = __import__(module if module is not None else '__main__')
|
|
183
|
+
for comp in parts[1:]:
|
|
184
|
+
m = getattr(m, comp)
|
|
185
|
+
return m
|
|
186
|
+
|
|
187
|
+
anson = getClass(typename)() if isinstance(typename, str) else typename()
|
|
188
|
+
|
|
189
|
+
fds = Anson.fields(anson)
|
|
190
|
+
if '__type__' not in fds:
|
|
191
|
+
raise Exception(f'Class {type(anson)} has no field "__type__". Is it a subclass of Anson?')
|
|
192
|
+
|
|
193
|
+
for jsonk in obj:
|
|
194
|
+
k = '__type__' if jsonk == 'type' else jsonk
|
|
195
|
+
if k != '__type__' and k not in fds:
|
|
196
|
+
Utils.warn(f'Field ignored: {k}: {obj[k]}')
|
|
197
|
+
continue
|
|
198
|
+
|
|
199
|
+
# else [Anson.from_obj(x, 'str' if thefields[k].elemtype is None else thefields[k].elemtype) for x in obj[jsonk]] if thefields[k].antype == 'obj' else \
|
|
200
|
+
anson[k] = Anson.from_obj(obj[jsonk], fds[k].antype) if fds[k].isAnson \
|
|
201
|
+
else Anson.from_dict(obj[jsonk], fds[k].elemtype) if fds[k].antype == 'obj'\
|
|
202
|
+
else Anson.from_list(obj[jsonk], fds[k].elemtype) if fds[k].antype == 'lst' \
|
|
203
|
+
else obj[jsonk]
|
|
204
|
+
|
|
205
|
+
return anson
|
|
206
|
+
|
|
207
|
+
@staticmethod
|
|
208
|
+
def from_json(jsonstr: str) -> TAnson:
|
|
209
|
+
obj = json.loads(jsonstr)
|
|
210
|
+
v = Anson.from_envelope(obj)
|
|
211
|
+
print(v, type(v))
|
|
212
|
+
return v
|
|
213
|
+
|
|
214
|
+
@staticmethod
|
|
215
|
+
def from_file(fp: str) -> TAnson:
|
|
216
|
+
with open(fp, 'r') as file:
|
|
217
|
+
obj = json.load(file)
|
|
218
|
+
return Anson.from_envelope(obj)
|
|
219
|
+
|
|
220
|
+
@classmethod
|
|
221
|
+
def java_src(cls, src_root: str = ''):
|
|
222
|
+
"""
|
|
223
|
+
:param src_root: e. g. 'src'
|
|
224
|
+
"""
|
|
225
|
+
global java_src_path
|
|
226
|
+
java_src_path = src_root
|
|
227
|
+
|
|
228
|
+
@classmethod
|
|
229
|
+
def from_envelope(cls, obj: dict):
|
|
230
|
+
return Anson.from_obj(obj,
|
|
231
|
+
'.'.join([java_src_path, obj['type']]) if len(java_src_path) > 0 else obj['type'])
|
anson/io/odysz/common.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Created on 25 Oct 2019
|
|
3
|
+
|
|
4
|
+
@author: odys-z@github.com
|
|
5
|
+
'''
|
|
6
|
+
import sys
|
|
7
|
+
from re import match
|
|
8
|
+
from typing import TextIO, Optional, TypeVar
|
|
9
|
+
|
|
10
|
+
T = TypeVar('T')
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LangExt:
|
|
14
|
+
'''
|
|
15
|
+
classdocs
|
|
16
|
+
'''
|
|
17
|
+
|
|
18
|
+
def __init__(self, params):
|
|
19
|
+
'''
|
|
20
|
+
Constructor
|
|
21
|
+
'''
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
def isblank(s, regex=None):
|
|
25
|
+
if (s == None):
|
|
26
|
+
return True
|
|
27
|
+
if isinstance(s, str):
|
|
28
|
+
if regex == None or s == "":
|
|
29
|
+
return len(s) == 0
|
|
30
|
+
else:
|
|
31
|
+
return match(s, regex)
|
|
32
|
+
return False
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def ifnull(a: T, b: T) -> T:
|
|
36
|
+
return b if a is None else a
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def len(cls, obj):
|
|
40
|
+
return 0 if obj is None else len(obj)
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def str(obj: dict | list):
|
|
44
|
+
def quot(v) -> str:
|
|
45
|
+
return f'"{v}"' if type(v) == str else f'"{v.toBlock()}"' if isinstance(v, Anson) else LangExt.str(v)
|
|
46
|
+
from src.anson.io.odysz.ansons import Anson
|
|
47
|
+
if type(obj) == dict:
|
|
48
|
+
s = '{'
|
|
49
|
+
for k, v in obj.items():
|
|
50
|
+
# s += f'{"" if len(s) == 1 else ",\n"}"{k}": "{LangExt.str(v)}"'
|
|
51
|
+
s += f'{"" if len(s) == 1 else ",\n"}"{k}": {quot(v)}'
|
|
52
|
+
s += '}'
|
|
53
|
+
return s
|
|
54
|
+
elif type(obj) == list:
|
|
55
|
+
s = '['
|
|
56
|
+
# s += ", ".join(f'"{x}"' if type(x) == str else LangExt.str(x) for x in obj)
|
|
57
|
+
s += ", ".join(quot(x) for x in obj)
|
|
58
|
+
return s + ']'
|
|
59
|
+
elif isinstance(obj, Anson):
|
|
60
|
+
return obj.toBlock()
|
|
61
|
+
else:
|
|
62
|
+
return str(obj)
|
|
63
|
+
|
|
64
|
+
def log(out: Optional[TextIO], templt: str, *args):
|
|
65
|
+
try:
|
|
66
|
+
print(templt if LangExt.isblank(args) else templt.format(*args), file=out)
|
|
67
|
+
except Exception as e:
|
|
68
|
+
print(templt, args, e)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Utils:
|
|
72
|
+
def __init__(self, params):
|
|
73
|
+
'''
|
|
74
|
+
Constructor
|
|
75
|
+
'''
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def logi(templt, *args):
|
|
79
|
+
log(sys.stdout, templt, *args)
|
|
80
|
+
|
|
81
|
+
@staticmethod
|
|
82
|
+
def warn(templt, *args):
|
|
83
|
+
log(sys.stderr, templt, *args)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: anson.py3
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Anson for Python3
|
|
5
|
+
Project-URL: Homepage, https://github.com/odys-z/antson
|
|
6
|
+
Project-URL: Issues, https://github.com/odys-z/antson/issues
|
|
7
|
+
Author-email: Ody Z <odys.zhou@gmail.com>
|
|
8
|
+
License: Copyright (c) 2025 Ody Z. All rights reserved.
|
|
9
|
+
|
|
10
|
+
This work is licensed under the terms of the MIT license.
|
|
11
|
+
For a copy, see <https://opensource.org/licenses/MIT>.
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# Anson.py3
|
|
19
|
+
|
|
20
|
+
A testing package ...
|
|
21
|
+
|
|
22
|
+
```code
|
|
23
|
+
from ansons.anson import Anson
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
# Install from testpypi
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
pip install --index-url https://test.pypi.org/simple --extra-index-url https://pypi.org/simple anson.py3
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
# Guide
|
|
33
|
+
|
|
34
|
+
- Mapping Java vs Python package structure
|
|
35
|
+
|
|
36
|
+
Python packages tree is in format of *path/to/module/class*, while java has no node of *module*:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
├── io
|
|
40
|
+
│ └── oz
|
|
41
|
+
│ ├── jserv
|
|
42
|
+
│ │ └── docs
|
|
43
|
+
│ │ └── syn
|
|
44
|
+
│ │ └── singleton.py "class AppSettings"
|
|
45
|
+
│ └── syn.py "class AnRegistry, SynodeConfig, SynOrg, YellowPages"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Java packages tree:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
.
|
|
52
|
+
└── io
|
|
53
|
+
└── oz
|
|
54
|
+
└── jserv
|
|
55
|
+
└── docs
|
|
56
|
+
└── syn
|
|
57
|
+
├── singleton
|
|
58
|
+
│ └── AppSettings.java
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
.
|
|
63
|
+
└── io
|
|
64
|
+
└── oz
|
|
65
|
+
└── syn
|
|
66
|
+
├── AnRegistry.java
|
|
67
|
+
├── SynodeConfig.java
|
|
68
|
+
├── SynOrg.java
|
|
69
|
+
└── YellowPages.java
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Anson.py3 is using package name path with a top level path. Say, if the json envelope
|
|
73
|
+
define as
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
{ type: io.oz.syn.AnRegistry,
|
|
77
|
+
...
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
and the user's project tree is:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
src
|
|
85
|
+
├── io
|
|
86
|
+
│ └── oz
|
|
87
|
+
│ ├── jserv
|
|
88
|
+
│ │ └── docs
|
|
89
|
+
│ │ └── syn
|
|
90
|
+
│ │ └── singleton.py "class AppSettings"
|
|
91
|
+
│ └── syn.py "class AnRegistry, SynodeConfig, SynOrg, YellowPages"
|
|
92
|
+
main.py
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
In main.py, call
|
|
96
|
+
|
|
97
|
+
```code
|
|
98
|
+
Anson.java_src('src')
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
before
|
|
102
|
+
|
|
103
|
+
```code
|
|
104
|
+
AnRegistry.from_file(path)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
# Issues
|
|
108
|
+
|
|
109
|
+
- Printing Anson subclasses with non-default field without value initialization will result in errors
|
|
110
|
+
|
|
111
|
+
If SynOrg.parent is defined as
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
class SynOrg(Anson)
|
|
115
|
+
parent: str
|
|
116
|
+
|
|
117
|
+
def __init__(self):
|
|
118
|
+
super().__init__()
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
org = Anson.from_file(...)
|
|
124
|
+
print (org)
|
|
125
|
+
|
|
126
|
+
Error
|
|
127
|
+
Traceback (most recent call last):
|
|
128
|
+
File "/home/antson/py3/test/testYellowPages.py", line 18, in testAnregistry
|
|
129
|
+
print(diction)
|
|
130
|
+
File "/usr/lib/python3.12/dataclasses.py", line 262, in wrapper
|
|
131
|
+
result = user_function(self)
|
|
132
|
+
^^^^^^^^^^^^^^^^^^^
|
|
133
|
+
File "<string>", line 3, in __repr__
|
|
134
|
+
File "/usr/lib/python3.12/dataclasses.py", line 262, in wrapper
|
|
135
|
+
result = user_function(self)
|
|
136
|
+
^^^^^^^^^^^^^^^^^^^
|
|
137
|
+
File "<string>", line 3, in __repr__
|
|
138
|
+
File "/usr/lib/python3.12/dataclasses.py", line 262, in wrapper
|
|
139
|
+
result = user_function(self)
|
|
140
|
+
^^^^^^^^^^^^^^^^^^^
|
|
141
|
+
File "<string>", line 3, in __repr__
|
|
142
|
+
AttributeError: 'SynOrg' object has no attribute 'parent'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
# References
|
|
146
|
+
|
|
147
|
+
- https://packaging.python.org/en/latest/tutorials/packaging-projects/
|
|
148
|
+
|
|
149
|
+
```python3 -m twine upload --repository testpypi dist/*```
|
|
150
|
+
|
|
151
|
+
# Troubleshootings
|
|
152
|
+
|
|
153
|
+
.pypirc
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
[testpypi]
|
|
157
|
+
repository: https://test.pypi.org/legacy/
|
|
158
|
+
username = __token__
|
|
159
|
+
password = pypi-zzz
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
python3 -m twine --version
|
|
164
|
+
twine version 6.1.0 (keyring: 25.6.0, packaging: 24.2, requests: 2.31.0, requests-toolbelt: 1.0.0,
|
|
165
|
+
urllib3: 2.0.7, id: 1.5.0)
|
|
166
|
+
python3 -m build
|
|
167
|
+
python3 -m twine upload --repository testpypi dist/*
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
ERROR InvalidDistribution: Invalid distribution metadata: unrecognized or malformed field
|
|
172
|
+
'license-file'; unrecognized or malformed field 'license-expression'
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Install twine 6.1.0 and packaging 24.
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
pip install packaging -U
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
See [issue #1216](https://github.com/pypa/twine/issues/1216#issuecomment-2609745412).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
anson/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
anson/io/odysz/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
anson/io/odysz/ansons.py,sha256=Na3MF9tnAIlssI3xMcrwcugEMUyzfApLHj1iHWk5ptY,8565
|
|
4
|
+
anson/io/odysz/common.py,sha256=wvuAAxciEsKGRwx2Y_2mAAJnA7PgvXtjnyuA-DhdXd4,2145
|
|
5
|
+
anson/io/odysz/anson/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
anson/io/odysz/anson/x/__init__.py,sha256=UHUOTmlyuMySt7cmaupaqy4fUDAJ1cH5oYhSElFcMaI,305
|
|
7
|
+
anson_py3-0.1.0.dist-info/METADATA,sha256=CvaI-KkpoIrU4uO3GS92ixExTUxVx_9QiuyVyEoTw6I,4134
|
|
8
|
+
anson_py3-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
9
|
+
anson_py3-0.1.0.dist-info/licenses/LICENSE,sha256=z_ecrO9KkQ-pyddGEAsjUEOS-igXLy4GnjQE2sEpwlo,1084
|
|
10
|
+
anson_py3-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 odys-z
|
|
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.
|