summaryrefslogtreecommitdiff
path: root/python-connexion-plus.spec
blob: 7afa8d1dde609302edd039a29e9e54b233a94ab4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
%global _empty_manifest_terminate_build 0
Name:		python-connexion-plus
Version:	0.49
Release:	1
Summary:	Connexion with benefits for microservices
License:	MIT
URL:		https://github.com/Heiss/connexion-plus
Source0:	https://mirrors.aliyun.com/pypi/web/packages/10/dd/eee3daa2e2cd81d59778026fb0e3f58ba7878ebb5abd6d5714b437911372/connexion-plus-0.49.tar.gz
BuildArch:	noarch

Requires:	python3-connexion
Requires:	python3-jaeger-client
Requires:	python3-prometheus-flask-exporter
Requires:	python3-requests
Requires:	python3-opentracing-instrumentation
Requires:	python3-Flask-Opentracing
Requires:	python3-htmlmin
Requires:	python3-flask-cors
Requires:	python3-Flask-APScheduler
Requires:	python3-redis-pubsub-dict-wo-cluster
Requires:	python3-redis

%description
[![PyPI version](https://badge.fury.io/py/connexion-plus.svg)](https://badge.fury.io/py/connexion-plus)![Workflow Status](https://github.com/Sciebo-RDS/connexion-plus/workflows/Publish%20Python%20%F0%9F%90%8D%20distributions%20%F0%9F%93%A6%20to%20PyPI%20and%20TestPyPI/badge.svg)

[Connexion](https://github.com/zalando/connexion) with benefits for microservices.

# Connexion Plus

If you want to use [Connexion](https://github.com/zalando/connexion) for your microservice, you have to add an [opentracing](https://opentracing.io/) or [prometheus](https://prometheus.io/) client on your own. With this library, you instantiate everything before your connexion app starts and this library will take care to put it all together, so you get everything fine.

> Currently this library works only for Flask!

This library give you a new class `App`, which you have to use instead of the connexion FlaskApp, to get everything working. The App inheritates from connexion app, so you can use it with your old code, but replace your import with `from connexion_plus import App`.

If you want to know more about the used libraries, please go to the corresponding documentaries.

## Dependencies

- [Connexion](https://github.com/zalando/connexion)
- [opentracing-python-instrumentation](https://github.com/uber-common/opentracing-python-instrumentation)
- [Flask-Opentracing](https://github.com/opentracing-contrib/python-flask)
- [jaeger-client](https://pypi.org/project/jaeger-client/)
- [requests](https://pypi.org/project/requests/)
- [prometheus-flask-exporter](https://pypi.org/project/prometheus-flask-exporter/)

## Importing

```python
from connexion_plus import App
```

## OpenTracing / Jaeger-Client

Currently, all opentracing implementation (e.g. [jaeger-client](https://pypi.org/project/jaeger-client/)) are supported for tracing. But this library use a third party function, that only supports Flask. If you want to use it, you have to initialize the client before you start your connexion app and give it via the `tracer`-parameter to the `connexion_plus` App, where the magic happens.

If you want to use a default tracer, you can use `use_tracer=True` simply.

The following example uses jaeger-client (`pip install jaeger-client`) implementation. (Currently installs with connexion-plus per default)

```python
from connexion_plus import App
from jaeger_client import Config as jConfig

config = jConfig(
        config={
            'logging': True,
        },
    )
jaeger_tracer = config.initialize_tracer()

app = App(__name__, use_tracer=jaeger_tracer)
```

If you use the tracer, you get also a TracingHandler in your logging module under the empty name, so your logging message can be logged with opentracing.

```python
logging.getLogger('')
```

You can edit the logging-level with the `use_logging_level`-parameter of the addServices-method. DEBUG is the default level, so you get everything from the log within a route in your opentracing-ui. (As long as there are a span while you write a logging message, you will see the logging message in your span)
```python
import logging
from connexion_plus import App

app = App(app, use_tracer=config.initialize_tracer(), use_logging_level=logging.DEBUG)
```

It improve the performance slightly, when you set the log-level to a higher level (INFO, WARNING).

## Prometheus / Metrics

Currently, it is only the [prometheus-flask-exporter](https://pypi.org/project/prometheus-flask-exporter/) supported for connexion, so only for flask connexion. You only have to set the `metrics`-parameter to `True`

```python
from connexion_plus import App

app = App(__name__, use_metric=True)
```

## Use a default error handler

For a faster implementation, you can use a default error handler. Set the parameter `use_default_handler` to True for use a simple default handler. Otherwise give a function / method to this parameter, which handles your exceptions.

## Complete example

If you want to use `tracer` and `metrics` together, see here a complete example. This currently works only with flask (see prometheus)

```python
from connexion_plus import App
from jaeger_client import Config as jConfig
from jaeger_client.metrics.prometheus import PrometheusMetricsFactory
import logging

config = jConfig(
        config={
            'logging': True,
        },
        # use this, if you want to track your tracing itself with prometheus
        metrics_factory = PrometheusMetricsFactory(namespace=name),
    )
jaeger_tracer = config.initialize_tracer()

app = App(name, use_tracer=config.initialize_tracer(), use_metric=True, use_optimizer=True, use_cors=True, use_logging_level=logging.DEBUG)
app.add_api('openapi.yaml', resolver=RestyResolver('api'))
```

If you add the line `metrics_factory=PrometheusMetricsFactory(namespace='yourAppName')` to your jaeger-client-config, you get the metrics out of jaeger into your flask app to track all metrics at once `/metrics`.

## More features

If you want to get the current tracing object in a request context, you can use [FlaskTracing](https://github.com/opentracing-contrib/python-flask#accessing-spans-manually)

```python
import Flasktracing
FlaskTracing.get_span(request)
```

If you get a collision of your view-functions, you can use `from connexion-plus.MultipleResourceResolver import MultipleResourceResolver` as a replacement for RestyResolver to get better control of multi resource path e.g. /resource1/{id1}/resource2/{id2} tries to find the classes *Resource1Resource2* or *resource1resource2* in the given "api" folder.

## Use of optimizer

If you want to use the optimizer or use custom configs for single routes, you can use the FlaskOptimize class `from connexion_plus import FlaskOptimize`.
This class has the methods `do_not_minify` (the decorated route will not minified before send), `do_not_compress` (the decorated route will not compressed before send) and `set_cache_timeout(seconds)` (default 24h) (the response from the decorated route will be cached until `seconds`).

Currently it is only be possible to deactivate the global config `use_optimizer` and not activate single routes with e.g. `minify`. This could be your first contributation to this project. :)

### Importing Multiple Resources

If you want to make usage of multiple resource in a single URL (e.g. /Res1/{Para1}/Res2), you can use the `from connexion-plus import MultiResourceResolver` as your connexion resolver. This resolves the example: `/Res1/{Para1}/Res2 resolves in Res1.Res2` and as a convenient function, it resolves also `/Res1/{Para1}/Res2 resolves in Res1Res2`, so you can choose both. The first one searches for folders and at last a file `Res1/Res2.py`. The second searches a file with this name `Res1Res2.py`. Currently no classes inside the files are supported.

If you want to add Methods to a resource (e.g. Res1 should answer for GET and POST), you have to add an `__init__.py` to the folder and import there your resource-file `from .Res1 import *`. If you use the second method, you don't have a folder and a file with the name `Res1`, so you don't need this workaround.

## Examples

You can find more examples in the [repo](https://github.com/Heiss/connexion-plus/tree/master/examples). *Tutorial1* is a simple small (without bonuscode) script without an openapi definition.
Please use *Tutorial2* if you want a complete usage example.

## Research data services

This library is under development for the project [research data services](http://research-data-services.info), a microservice ecosystem.


%package -n python3-connexion-plus
Summary:	Connexion with benefits for microservices
Provides:	python-connexion-plus
BuildRequires:	python3-devel
BuildRequires:	python3-setuptools
BuildRequires:	python3-pip
%description -n python3-connexion-plus
[![PyPI version](https://badge.fury.io/py/connexion-plus.svg)](https://badge.fury.io/py/connexion-plus)![Workflow Status](https://github.com/Sciebo-RDS/connexion-plus/workflows/Publish%20Python%20%F0%9F%90%8D%20distributions%20%F0%9F%93%A6%20to%20PyPI%20and%20TestPyPI/badge.svg)

[Connexion](https://github.com/zalando/connexion) with benefits for microservices.

# Connexion Plus

If you want to use [Connexion](https://github.com/zalando/connexion) for your microservice, you have to add an [opentracing](https://opentracing.io/) or [prometheus](https://prometheus.io/) client on your own. With this library, you instantiate everything before your connexion app starts and this library will take care to put it all together, so you get everything fine.

> Currently this library works only for Flask!

This library give you a new class `App`, which you have to use instead of the connexion FlaskApp, to get everything working. The App inheritates from connexion app, so you can use it with your old code, but replace your import with `from connexion_plus import App`.

If you want to know more about the used libraries, please go to the corresponding documentaries.

## Dependencies

- [Connexion](https://github.com/zalando/connexion)
- [opentracing-python-instrumentation](https://github.com/uber-common/opentracing-python-instrumentation)
- [Flask-Opentracing](https://github.com/opentracing-contrib/python-flask)
- [jaeger-client](https://pypi.org/project/jaeger-client/)
- [requests](https://pypi.org/project/requests/)
- [prometheus-flask-exporter](https://pypi.org/project/prometheus-flask-exporter/)

## Importing

```python
from connexion_plus import App
```

## OpenTracing / Jaeger-Client

Currently, all opentracing implementation (e.g. [jaeger-client](https://pypi.org/project/jaeger-client/)) are supported for tracing. But this library use a third party function, that only supports Flask. If you want to use it, you have to initialize the client before you start your connexion app and give it via the `tracer`-parameter to the `connexion_plus` App, where the magic happens.

If you want to use a default tracer, you can use `use_tracer=True` simply.

The following example uses jaeger-client (`pip install jaeger-client`) implementation. (Currently installs with connexion-plus per default)

```python
from connexion_plus import App
from jaeger_client import Config as jConfig

config = jConfig(
        config={
            'logging': True,
        },
    )
jaeger_tracer = config.initialize_tracer()

app = App(__name__, use_tracer=jaeger_tracer)
```

If you use the tracer, you get also a TracingHandler in your logging module under the empty name, so your logging message can be logged with opentracing.

```python
logging.getLogger('')
```

You can edit the logging-level with the `use_logging_level`-parameter of the addServices-method. DEBUG is the default level, so you get everything from the log within a route in your opentracing-ui. (As long as there are a span while you write a logging message, you will see the logging message in your span)
```python
import logging
from connexion_plus import App

app = App(app, use_tracer=config.initialize_tracer(), use_logging_level=logging.DEBUG)
```

It improve the performance slightly, when you set the log-level to a higher level (INFO, WARNING).

## Prometheus / Metrics

Currently, it is only the [prometheus-flask-exporter](https://pypi.org/project/prometheus-flask-exporter/) supported for connexion, so only for flask connexion. You only have to set the `metrics`-parameter to `True`

```python
from connexion_plus import App

app = App(__name__, use_metric=True)
```

## Use a default error handler

For a faster implementation, you can use a default error handler. Set the parameter `use_default_handler` to True for use a simple default handler. Otherwise give a function / method to this parameter, which handles your exceptions.

## Complete example

If you want to use `tracer` and `metrics` together, see here a complete example. This currently works only with flask (see prometheus)

```python
from connexion_plus import App
from jaeger_client import Config as jConfig
from jaeger_client.metrics.prometheus import PrometheusMetricsFactory
import logging

config = jConfig(
        config={
            'logging': True,
        },
        # use this, if you want to track your tracing itself with prometheus
        metrics_factory = PrometheusMetricsFactory(namespace=name),
    )
jaeger_tracer = config.initialize_tracer()

app = App(name, use_tracer=config.initialize_tracer(), use_metric=True, use_optimizer=True, use_cors=True, use_logging_level=logging.DEBUG)
app.add_api('openapi.yaml', resolver=RestyResolver('api'))
```

If you add the line `metrics_factory=PrometheusMetricsFactory(namespace='yourAppName')` to your jaeger-client-config, you get the metrics out of jaeger into your flask app to track all metrics at once `/metrics`.

## More features

If you want to get the current tracing object in a request context, you can use [FlaskTracing](https://github.com/opentracing-contrib/python-flask#accessing-spans-manually)

```python
import Flasktracing
FlaskTracing.get_span(request)
```

If you get a collision of your view-functions, you can use `from connexion-plus.MultipleResourceResolver import MultipleResourceResolver` as a replacement for RestyResolver to get better control of multi resource path e.g. /resource1/{id1}/resource2/{id2} tries to find the classes *Resource1Resource2* or *resource1resource2* in the given "api" folder.

## Use of optimizer

If you want to use the optimizer or use custom configs for single routes, you can use the FlaskOptimize class `from connexion_plus import FlaskOptimize`.
This class has the methods `do_not_minify` (the decorated route will not minified before send), `do_not_compress` (the decorated route will not compressed before send) and `set_cache_timeout(seconds)` (default 24h) (the response from the decorated route will be cached until `seconds`).

Currently it is only be possible to deactivate the global config `use_optimizer` and not activate single routes with e.g. `minify`. This could be your first contributation to this project. :)

### Importing Multiple Resources

If you want to make usage of multiple resource in a single URL (e.g. /Res1/{Para1}/Res2), you can use the `from connexion-plus import MultiResourceResolver` as your connexion resolver. This resolves the example: `/Res1/{Para1}/Res2 resolves in Res1.Res2` and as a convenient function, it resolves also `/Res1/{Para1}/Res2 resolves in Res1Res2`, so you can choose both. The first one searches for folders and at last a file `Res1/Res2.py`. The second searches a file with this name `Res1Res2.py`. Currently no classes inside the files are supported.

If you want to add Methods to a resource (e.g. Res1 should answer for GET and POST), you have to add an `__init__.py` to the folder and import there your resource-file `from .Res1 import *`. If you use the second method, you don't have a folder and a file with the name `Res1`, so you don't need this workaround.

## Examples

You can find more examples in the [repo](https://github.com/Heiss/connexion-plus/tree/master/examples). *Tutorial1* is a simple small (without bonuscode) script without an openapi definition.
Please use *Tutorial2* if you want a complete usage example.

## Research data services

This library is under development for the project [research data services](http://research-data-services.info), a microservice ecosystem.


%package help
Summary:	Development documents and examples for connexion-plus
Provides:	python3-connexion-plus-doc
%description help
[![PyPI version](https://badge.fury.io/py/connexion-plus.svg)](https://badge.fury.io/py/connexion-plus)![Workflow Status](https://github.com/Sciebo-RDS/connexion-plus/workflows/Publish%20Python%20%F0%9F%90%8D%20distributions%20%F0%9F%93%A6%20to%20PyPI%20and%20TestPyPI/badge.svg)

[Connexion](https://github.com/zalando/connexion) with benefits for microservices.

# Connexion Plus

If you want to use [Connexion](https://github.com/zalando/connexion) for your microservice, you have to add an [opentracing](https://opentracing.io/) or [prometheus](https://prometheus.io/) client on your own. With this library, you instantiate everything before your connexion app starts and this library will take care to put it all together, so you get everything fine.

> Currently this library works only for Flask!

This library give you a new class `App`, which you have to use instead of the connexion FlaskApp, to get everything working. The App inheritates from connexion app, so you can use it with your old code, but replace your import with `from connexion_plus import App`.

If you want to know more about the used libraries, please go to the corresponding documentaries.

## Dependencies

- [Connexion](https://github.com/zalando/connexion)
- [opentracing-python-instrumentation](https://github.com/uber-common/opentracing-python-instrumentation)
- [Flask-Opentracing](https://github.com/opentracing-contrib/python-flask)
- [jaeger-client](https://pypi.org/project/jaeger-client/)
- [requests](https://pypi.org/project/requests/)
- [prometheus-flask-exporter](https://pypi.org/project/prometheus-flask-exporter/)

## Importing

```python
from connexion_plus import App
```

## OpenTracing / Jaeger-Client

Currently, all opentracing implementation (e.g. [jaeger-client](https://pypi.org/project/jaeger-client/)) are supported for tracing. But this library use a third party function, that only supports Flask. If you want to use it, you have to initialize the client before you start your connexion app and give it via the `tracer`-parameter to the `connexion_plus` App, where the magic happens.

If you want to use a default tracer, you can use `use_tracer=True` simply.

The following example uses jaeger-client (`pip install jaeger-client`) implementation. (Currently installs with connexion-plus per default)

```python
from connexion_plus import App
from jaeger_client import Config as jConfig

config = jConfig(
        config={
            'logging': True,
        },
    )
jaeger_tracer = config.initialize_tracer()

app = App(__name__, use_tracer=jaeger_tracer)
```

If you use the tracer, you get also a TracingHandler in your logging module under the empty name, so your logging message can be logged with opentracing.

```python
logging.getLogger('')
```

You can edit the logging-level with the `use_logging_level`-parameter of the addServices-method. DEBUG is the default level, so you get everything from the log within a route in your opentracing-ui. (As long as there are a span while you write a logging message, you will see the logging message in your span)
```python
import logging
from connexion_plus import App

app = App(app, use_tracer=config.initialize_tracer(), use_logging_level=logging.DEBUG)
```

It improve the performance slightly, when you set the log-level to a higher level (INFO, WARNING).

## Prometheus / Metrics

Currently, it is only the [prometheus-flask-exporter](https://pypi.org/project/prometheus-flask-exporter/) supported for connexion, so only for flask connexion. You only have to set the `metrics`-parameter to `True`

```python
from connexion_plus import App

app = App(__name__, use_metric=True)
```

## Use a default error handler

For a faster implementation, you can use a default error handler. Set the parameter `use_default_handler` to True for use a simple default handler. Otherwise give a function / method to this parameter, which handles your exceptions.

## Complete example

If you want to use `tracer` and `metrics` together, see here a complete example. This currently works only with flask (see prometheus)

```python
from connexion_plus import App
from jaeger_client import Config as jConfig
from jaeger_client.metrics.prometheus import PrometheusMetricsFactory
import logging

config = jConfig(
        config={
            'logging': True,
        },
        # use this, if you want to track your tracing itself with prometheus
        metrics_factory = PrometheusMetricsFactory(namespace=name),
    )
jaeger_tracer = config.initialize_tracer()

app = App(name, use_tracer=config.initialize_tracer(), use_metric=True, use_optimizer=True, use_cors=True, use_logging_level=logging.DEBUG)
app.add_api('openapi.yaml', resolver=RestyResolver('api'))
```

If you add the line `metrics_factory=PrometheusMetricsFactory(namespace='yourAppName')` to your jaeger-client-config, you get the metrics out of jaeger into your flask app to track all metrics at once `/metrics`.

## More features

If you want to get the current tracing object in a request context, you can use [FlaskTracing](https://github.com/opentracing-contrib/python-flask#accessing-spans-manually)

```python
import Flasktracing
FlaskTracing.get_span(request)
```

If you get a collision of your view-functions, you can use `from connexion-plus.MultipleResourceResolver import MultipleResourceResolver` as a replacement for RestyResolver to get better control of multi resource path e.g. /resource1/{id1}/resource2/{id2} tries to find the classes *Resource1Resource2* or *resource1resource2* in the given "api" folder.

## Use of optimizer

If you want to use the optimizer or use custom configs for single routes, you can use the FlaskOptimize class `from connexion_plus import FlaskOptimize`.
This class has the methods `do_not_minify` (the decorated route will not minified before send), `do_not_compress` (the decorated route will not compressed before send) and `set_cache_timeout(seconds)` (default 24h) (the response from the decorated route will be cached until `seconds`).

Currently it is only be possible to deactivate the global config `use_optimizer` and not activate single routes with e.g. `minify`. This could be your first contributation to this project. :)

### Importing Multiple Resources

If you want to make usage of multiple resource in a single URL (e.g. /Res1/{Para1}/Res2), you can use the `from connexion-plus import MultiResourceResolver` as your connexion resolver. This resolves the example: `/Res1/{Para1}/Res2 resolves in Res1.Res2` and as a convenient function, it resolves also `/Res1/{Para1}/Res2 resolves in Res1Res2`, so you can choose both. The first one searches for folders and at last a file `Res1/Res2.py`. The second searches a file with this name `Res1Res2.py`. Currently no classes inside the files are supported.

If you want to add Methods to a resource (e.g. Res1 should answer for GET and POST), you have to add an `__init__.py` to the folder and import there your resource-file `from .Res1 import *`. If you use the second method, you don't have a folder and a file with the name `Res1`, so you don't need this workaround.

## Examples

You can find more examples in the [repo](https://github.com/Heiss/connexion-plus/tree/master/examples). *Tutorial1* is a simple small (without bonuscode) script without an openapi definition.
Please use *Tutorial2* if you want a complete usage example.

## Research data services

This library is under development for the project [research data services](http://research-data-services.info), a microservice ecosystem.


%prep
%autosetup -n connexion-plus-0.49

%build
%py3_build

%install
%py3_install
install -d -m755 %{buildroot}/%{_pkgdocdir}
if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
pushd %{buildroot}
if [ -d usr/lib ]; then
	find usr/lib -type f -printf "\"/%h/%f\"\n" >> filelist.lst
fi
if [ -d usr/lib64 ]; then
	find usr/lib64 -type f -printf "\"/%h/%f\"\n" >> filelist.lst
fi
if [ -d usr/bin ]; then
	find usr/bin -type f -printf "\"/%h/%f\"\n" >> filelist.lst
fi
if [ -d usr/sbin ]; then
	find usr/sbin -type f -printf "\"/%h/%f\"\n" >> filelist.lst
fi
touch doclist.lst
if [ -d usr/share/man ]; then
	find usr/share/man -type f -printf "\"/%h/%f.gz\"\n" >> doclist.lst
fi
popd
mv %{buildroot}/filelist.lst .
mv %{buildroot}/doclist.lst .

%files -n python3-connexion-plus -f filelist.lst
%dir %{python3_sitelib}/*

%files help -f doclist.lst
%{_docdir}/*

%changelog
* Thu Jun 08 2023 Python_Bot <Python_Bot@openeuler.org> - 0.49-1
- Package Spec generated