Package: pydic
ParametersThepydic.Parametersclass is a simple container for key/value pairs.The available methods are:set(key, value): Sets a parameter.get(key, default=None): Returns a parameter by name. If the key don’t exists, the default parameter will be returned.has(key): ReturnsTrueif the parameter exists,Falseotherwise.remove(key): Removes a parameter.add(parameters): Adds a dict of parametersall(): Returns all set parameters.count(): Returns the number of all set parameters.keys(): Returns the all set parameter keys.parse_text(text): Resolves a string which can contain parameters (example: ‘Hello {{ name }} {{ surname }}!’)NoteYou can reference others parameters wrapping it between{{}}characters.For example:'foo': '{{ bar}}','bar': 'aaa', if you get thefooparameter, the return value should beaaabecausefoo->{{ bar }}->bar->aaaYou can escape brackets processing with “\”.For example, if you set a parameter with the following valueHello\{\{name\}\}, if you get it, the return will beHello {{ name }}!ServicesWhat is a Service ContainerA Service Container (ordependency injection container) is simply a python object that manages the instantiation of services (objects).
For example, suppose you have a simple python class that delivers email messages. Without a service container, you must manually create the object whenever you need it:frommyapplication.mailerimportMailermailer=Mailer('sendmail')mailer.send('felix@example.com',...)This is easy enough. The imaginaryMailerclass allows you to configure the method used to deliver the
email messages (e.g.sendmail,smtp, etc).But what if you wanted to use the mailer service somewhere else? You certainly don’t want to repeat the mailer
configuration every time you need to use the Mailer object. What if you needed to change thetransportfromsendmailtosmtpeverywhere in the application? You’d need to hunt down every place you create aMailerservice and change it.The Services container allows you to standardize and centralize the way objects are constructed in your application.Creating/Configuring Services in the ContainerA better answer is to let the service container create theMailerobject for you.
In order for this to work, you must teach the container how to create theMailerservice.
This is done via configuration definitions:...frompydicimportServicesdefinitions={'my_mailer':{'class':'myapplication.mailer.Mailer','arguments':['sendmail']}}services=Services(definitions)...When you ask for themy_mailerservice from the containerservices.get('my_mailer'), the container constructs the object and returns it.This is another major advantage of using the service container. Namely, a service is never constructed until it’s needed.
If you define a service and never use it, the service is never created. This saves memory and increases
the speed of your application. This also means that there’s very little or no performance hit for defining lots
of services.Services that are never used are never constructed.As an added bonus, theMailerservice is only created once and the same instance is returned each time you ask for
the service. This is almost always the behavior you’ll need (it’s more flexible and powerful).You can pass the arguments as list or dict.Also you can call functions after object instantiation with:...definitions={'my_mailer':{'class':'myapplication.mailer.Mailer','arguments':['sendmail'],'calls':[['set_name','Felix Carmona'],['inject_something',[1,2,3]],['inject_something',[2,3]],['set_location',{'city':'Barcelona','country':'Spain'}]]}}...Once the container has been constructed with the definitions, the available methods for the service container object are:set(key, value): Sets a service object by name.get(key): Returns a service object by name.has(key): ReturnsTrueif the service definition exists or if the service object is instantiated,Falseotherwise.remove(key): Removes a service object and service definition by name.add(parameters): Adds a dict of services objects.keys(): Returns the services keys.Using the Parameters to build ServicesThe creation of new services (objects) via the container is pretty straightforward. Parameters make defining services
more organized and flexible:...parameters=Parameters({'my_mailer_class':'myapplication.mailer.Mailer','my_mailer_transport':'sendmail'})definitions={'my_mailer':{'class':'{{ my_mailer_class }}','arguments':['{{ my_mailer_transport }}']}}services=Services(definitions,parameters)...The end result is exactly the same as before - the difference is only in how you defined the service.
By surrounding themy_mailer.classandmy_mailer.transportstrings in double bracket keys ({{}}) signs, the services container knows to look
for parameters with those names. Parameters can deep reference other parameters that references other parameters, and will
be resolved anyway.The purpose of parameters is to feed information into services. Of course there was nothing wrong with defining the
service without using any parameters. Parameters, however, have several advantages:separation and organization of all service “options” under a single parameters keyparameter values can be used in multiple service definitionsThe choice of using or not using parameters is up to you.Referencing (Injecting) ServicesYou can of course also reference servicesStart the string with @ to reference a service, example:...parameters=Parameters({'my_mailer_class':'myapplication.mailer.Mailer','my_mailer_transport':'sendmail'})definitions={'my_mailer':{'class':'{{ my_mailer_class }}','arguments':['{{ my_mailer_transport }}']},'my_mailer_manager':{}'class':'myapplication.mailer.MailerManager','arguments':['@my_mailer']}}services=Services(definitions,parameters)...themy_mailerservice will be injected in themy_mailer_managerNoteUse@@to escape the@symbol.@@my_mailerwill be converted into the string “@my_mailer” instead of referencing themy_mailerservice.pydic is open-sourced software licensed under the MIT license