• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ets-labs / python-dependency-injector / 11658381748

04 Nov 2024 05:04AM UTC coverage: 94.246%. Remained the same
11658381748

Pull #826

github

web-flow
Bump werkzeug from 2.2.2 to 3.0.6

Bumps [werkzeug](https://github.com/pallets/werkzeug) from 2.2.2 to 3.0.6.
- [Release notes](https://github.com/pallets/werkzeug/releases)
- [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/werkzeug/compare/2.2.2...3.0.6)

---
updated-dependencies:
- dependency-name: werkzeug
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #826: Bump werkzeug from 2.2.2 to 3.0.6

3325 of 3528 relevant lines covered (94.25%)

0.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.1
/src/dependency_injector/containers.pyx
1
"""Containers module."""
1✔
2

3
import contextlib
1✔
4
import copy as copy_module
1✔
5
import json
1✔
6
import sys
1✔
7
import importlib
1✔
8
import inspect
1✔
9
import warnings
1✔
10

11
try:
1✔
12
    import asyncio
1✔
13
except ImportError:
×
14
    asyncio = None
×
15

16
try:
1✔
17
    import yaml
1✔
18
except ImportError:
×
19
    yaml = None
×
20

21
import six
1✔
22

23
from . import providers, errors
1✔
24
from .providers cimport __is_future_or_coroutine
25

26

27
if sys.version_info[:2] >= (3, 6):
1✔
28
    from .wiring import wire, unwire
1✔
29
else:
30
    def wire(*args, **kwargs):
×
31
        raise NotImplementedError("Wiring requires Python 3.6 or above")
×
32

33
    def unwire(*args, **kwargs):
×
34
        raise NotImplementedError("Wiring requires Python 3.6 or above")
×
35

36
if sys.version_info[:2] == (3, 5):
1✔
37
    warnings.warn(
×
38
        "Dependency Injector will drop support of Python 3.5 after Jan 1st of 2022. "
39
        "This does not mean that there will be any immediate breaking changes, "
40
        "but tests will no longer be executed on Python 3.5, and bugs will not be addressed.",
41
        category=DeprecationWarning,
×
42
    )
43

44

45
class WiringConfiguration:
1✔
46
    """Container wiring configuration."""
47

48
    def __init__(self, modules=None, packages=None, from_package=None, auto_wire=True):
1✔
49
        self.modules = [*modules] if modules else []
1✔
50
        self.packages = [*packages] if packages else []
1✔
51
        self.from_package = from_package
1✔
52
        self.auto_wire = auto_wire
1✔
53

54
    def __deepcopy__(self, memo=None):
1✔
55
        return self.__class__(self.modules, self.packages, self.from_package, self.auto_wire)
1✔
56

57

58
class Container(object):
1✔
59
    """Abstract container."""
60

61

62
class DynamicContainer(Container):
1✔
63
    """Dynamic inversion of control container.
64

65
    .. code-block:: python
66

67
        services = DynamicContainer()
68
        services.auth = providers.Factory(AuthService)
69
        services.users = providers.Factory(UsersService,
70
                                           auth_service=services.auth)
71

72
    .. py:attribute:: providers
73

74
        Read-only dictionary of all providers.
75

76
        :type: dict[str, :py:class:`dependency_injector.providers.Provider`]
77

78
    .. py:attribute:: overridden
79

80
        Tuple of overriding containers.
81

82
        :type: tuple[:py:class:`DynamicContainer`]
83

84
    .. py:attribute:: provider_type
85

86
        Type of providers that could be placed in container.
87

88
        :type: type
89
    """
90

91
    __IS_CONTAINER__ = True
1✔
92

93
    def __init__(self):
1✔
94
        """Initializer.
95

96
        :rtype: None
97
        """
98
        self.provider_type = providers.Provider
1✔
99
        self.providers = {}
1✔
100
        self.overridden = tuple()
1✔
101
        self.parent = None
1✔
102
        self.declarative_parent = None
1✔
103
        self.wiring_config = WiringConfiguration()
1✔
104
        self.wired_to_modules = []
1✔
105
        self.wired_to_packages = []
1✔
106
        self.__self__ = providers.Self(self)
1✔
107
        super(DynamicContainer, self).__init__()
1✔
108

109
    def __deepcopy__(self, memo):
1✔
110
        """Create and return full copy of container."""
111
        copied = memo.get(id(self))
1✔
112
        if copied is not None:
1✔
113
            return copied
×
114

115
        copied = self.__class__()
1✔
116
        memo[id(self)] = copied
1✔
117

118
        copied.__self__ = providers.deepcopy(self.__self__, memo)
1✔
119
        for name in copied.__self__.alt_names:
1✔
120
            copied.set_provider(name, copied.__self__)
1✔
121

122
        copied.provider_type = providers.Provider
1✔
123
        copied.overridden = providers.deepcopy(self.overridden, memo)
1✔
124
        copied.wiring_config = copy_module.deepcopy(self.wiring_config, memo)
1✔
125
        copied.declarative_parent = self.declarative_parent
1✔
126

127
        for name, provider in providers.deepcopy(self.providers, memo).items():
1✔
128
            copied.set_provider(name, provider)
1✔
129

130
        copied.parent = providers.deepcopy(self.parent, memo)
1✔
131

132
        return copied
1✔
133

134
    def __setattr__(self, name, value):
1✔
135
        """Set instance attribute.
136

137
        If value of attribute is provider, it will be added into providers
138
        dictionary.
139

140
        :param name: Attribute name
141
        :type name: object
142

143
        :param value: Attribute value
144
        :type value: object
145

146
        :rtype: None
147
        """
148
        if isinstance(value, providers.Provider) \
1✔
149
                and not isinstance(value, providers.Self) \
1✔
150
                and name != "parent":
1✔
151
            _check_provider_type(self, value)
1✔
152

153
            self.providers[name] = value
1✔
154

155
            if isinstance(value, providers.CHILD_PROVIDERS):
1✔
156
                value.assign_parent(self)
1✔
157

158
        super(DynamicContainer, self).__setattr__(name, value)
1✔
159

160
    def __delattr__(self, name):
1✔
161
        """Delete instance attribute.
162

163
        If value of attribute is provider, it will be deleted from providers
164
        dictionary.
165

166
        :param name: Attribute name
167
        :type name: object
168

169
        :rtype: None
170
        """
171
        if name in self.providers:
1✔
172
            del self.providers[name]
1✔
173
        super(DynamicContainer, self).__delattr__(name)
1✔
174

175
    @property
1✔
176
    def dependencies(self):
177
        """Return dependency providers dictionary.
178

179
        Dependency providers can be both of :py:class:`dependency_injector.providers.Dependency` and
180
        :py:class:`dependency_injector.providers.DependenciesContainer`.
181

182
        :rtype:
183
            dict[str, :py:class:`dependency_injector.providers.Provider`]
184
        """
185
        return {
1✔
186
            name: provider
1✔
187
            for name, provider in self.providers.items()
1✔
188
            if isinstance(provider, (providers.Dependency, providers.DependenciesContainer))
1✔
189
        }
190

191
    def traverse(self, types=None):
1✔
192
        """Return providers traversal generator."""
193
        yield from providers.traverse(*self.providers.values(), types=types)
1✔
194

195
    def set_providers(self, **providers):
1✔
196
        """Set container providers.
197

198
        :param providers: Dictionary of providers
199
        :type providers:
200
            dict[object, :py:class:`dependency_injector.providers.Provider`]
201

202
        :rtype: None
203
        """
204
        for name, provider in six.iteritems(providers):
1✔
205
            setattr(self, name, provider)
1✔
206

207
    def set_provider(self, name, provider):
1✔
208
        """Set container provider.
209

210
        :param name: Provider name
211
        :type name: str
212

213
        :param provider: Provider
214
        :type provider: :py:class:`dependency_injector.providers.Provider`
215

216
        :rtype: None
217
        """
218
        setattr(self, name, provider)
1✔
219

220
    def override(self, object overriding):
1✔
221
        """Override current container by overriding container.
222

223
        :param overriding: Overriding container.
224
        :type overriding: :py:class:`DynamicContainer`
225

226
        :raise: :py:exc:`dependency_injector.errors.Error` if trying to
227
                override container by itself
228

229
        :rtype: None
230
        """
231
        if overriding is self:
1✔
232
            raise errors.Error("Container {0} could not be overridden "
1✔
233
                               "with itself".format(self))
1✔
234

235
        self.overridden += (overriding,)
1✔
236

237
        for name, provider in six.iteritems(overriding.providers):
1✔
238
            try:
1✔
239
                getattr(self, name).override(provider)
1✔
240
            except AttributeError:
1✔
241
                pass
242

243
    def override_providers(self, **overriding_providers):
1✔
244
        """Override container providers.
245

246
        :param overriding_providers: Dictionary of providers
247
        :type overriding_providers:
248
            dict[str, :py:class:`dependency_injector.providers.Provider`]
249

250
        :rtype: None
251
        """
252
        overridden_providers = []
1✔
253
        for name, overriding_provider in six.iteritems(overriding_providers):
1✔
254
            container_provider = getattr(self, name)
1✔
255
            container_provider.override(overriding_provider)
1✔
256
            overridden_providers.append(container_provider)
1✔
257
        return ProvidersOverridingContext(self, overridden_providers)
1✔
258

259
    def reset_last_overriding(self):
1✔
260
        """Reset last overriding provider for each container providers.
261

262
        :rtype: None
263
        """
264
        if not self.overridden:
1✔
265
            raise errors.Error("Container {0} is not overridden".format(self))
1✔
266

267
        self.overridden = self.overridden[:-1]
1✔
268

269
        for provider in six.itervalues(self.providers):
1✔
270
            provider.reset_last_overriding()
1✔
271

272
    def reset_override(self):
1✔
273
        """Reset all overridings for each container providers.
274

275
        :rtype: None
276
        """
277
        self.overridden = tuple()
1✔
278

279
        for provider in six.itervalues(self.providers):
1✔
280
            provider.reset_override()
1✔
281

282
    def is_auto_wiring_enabled(self):
1✔
283
        """Check if auto wiring is needed."""
284
        return self.wiring_config.auto_wire is True
1✔
285

286
    def wire(self, modules=None, packages=None, from_package=None):
1✔
287
        """Wire container providers with provided packages and modules.
288

289
        :rtype: None
290
        """
291
        if modules is None and self.wiring_config.modules:
1✔
292
            modules = self.wiring_config.modules
1✔
293
        if packages is None and self.wiring_config.packages:
1✔
294
            packages = self.wiring_config.packages
1✔
295

296
        modules = [*modules] if modules else []
1✔
297
        packages = [*packages] if packages else []
1✔
298

299
        if _any_relative_string_imports_in(modules) or _any_relative_string_imports_in(packages):
1✔
300
            if from_package is None:
1✔
301
                if self.wiring_config.from_package is not None:
1✔
302
                    from_package = self.wiring_config.from_package
1✔
303
                elif self.declarative_parent is not None \
1✔
304
                        and (self.wiring_config.modules or self.wiring_config.packages):
1✔
305
                    with contextlib.suppress(Exception):
1✔
306
                        from_package = _resolve_package_name_from_cls(self.declarative_parent)
1✔
307
                else:
308
                    with contextlib.suppress(Exception):
1✔
309
                        from_package = _resolve_calling_package_name()
1✔
310

311
        modules = _resolve_string_imports(modules, from_package)
1✔
312
        packages = _resolve_string_imports(packages, from_package)
1✔
313

314
        if not modules and not packages:
1✔
315
            return
1✔
316

317
        wire(
1✔
318
            container=self,
1✔
319
            modules=modules,
1✔
320
            packages=packages,
1✔
321
        )
322

323
        if modules:
1✔
324
            self.wired_to_modules.extend(modules)
1✔
325
        if packages:
1✔
326
            self.wired_to_packages.extend(packages)
1✔
327

328
    def unwire(self):
1✔
329
        """Unwire container providers from previously wired packages and modules."""
330
        unwire(
1✔
331
            modules=self.wired_to_modules,
1✔
332
            packages=self.wired_to_packages,
1✔
333
        )
334

335
        self.wired_to_modules.clear()
1✔
336
        self.wired_to_packages.clear()
1✔
337

338
    def init_resources(self):
1✔
339
        """Initialize all container resources."""
340
        futures = []
1✔
341

342
        for provider in self.traverse(types=[providers.Resource]):
1✔
343
            resource = provider.init()
1✔
344

345
            if __is_future_or_coroutine(resource):
1✔
346
                futures.append(resource)
1✔
347

348
        if futures:
1✔
349
            return asyncio.gather(*futures)
1✔
350

351
    def shutdown_resources(self):
1✔
352
        """Shutdown all container resources."""
353
        def _independent_resources(resources):
1✔
354
            for resource in resources:
1✔
355
                for other_resource in resources:
1✔
356
                    if not other_resource.initialized:
1✔
357
                        continue
1✔
358
                    if resource in other_resource.related:
1✔
359
                        break
1✔
360
                else:
361
                    yield resource
1✔
362

363
        async def _async_ordered_shutdown(resources):
1✔
364
            while any(resource.initialized for resource in resources):
1✔
365
                resources_to_shutdown = list(_independent_resources(resources))
1✔
366
                if not resources_to_shutdown:
1✔
367
                    raise RuntimeError("Unable to resolve resources shutdown order")
1✔
368
                futures = []
1✔
369
                for resource in resources_to_shutdown:
1✔
370
                    result = resource.shutdown()
1✔
371
                    if __is_future_or_coroutine(result):
1✔
372
                        futures.append(result)
1✔
373
                await asyncio.gather(*futures)
1✔
374

375
        def _sync_ordered_shutdown(resources):
1✔
376
            while any(resource.initialized for resource in resources):
1✔
377
                resources_to_shutdown = list(_independent_resources(resources))
1✔
378
                if not resources_to_shutdown:
1✔
379
                    raise RuntimeError("Unable to resolve resources shutdown order")
1✔
380
                for resource in resources_to_shutdown:
1✔
381
                    resource.shutdown()
1✔
382

383
        resources = list(self.traverse(types=[providers.Resource]))
1✔
384
        if any(resource.is_async_mode_enabled() for resource in resources):
1✔
385
            return _async_ordered_shutdown(resources)
1✔
386
        else:
387
            return _sync_ordered_shutdown(resources)
1✔
388

389
    def load_config(self):
1✔
390
        """Load configuration."""
391
        config: providers.Configuration
392
        for config in self.traverse(types=[providers.Configuration]):
1✔
393
            config.load()
1✔
394

395
    def apply_container_providers_overridings(self):
1✔
396
        """Apply container providers overridings."""
397
        for provider in self.traverse(types=[providers.Container]):
1✔
398
            provider.apply_overridings()
1✔
399

400
    def reset_singletons(self):
1✔
401
        """Reset container singletons."""
402
        for provider in self.traverse(types=[providers.BaseSingleton]):
1✔
403
            provider.reset()
1✔
404
        return SingletonResetContext(self)
1✔
405

406
    def check_dependencies(self):
1✔
407
        """Check if container dependencies are defined.
408

409
        If any dependency is undefined, raises an error.
410
        """
411
        undefined = [
1✔
412
            dependency
1✔
413
            for dependency in self.traverse(types=[providers.Dependency])
1✔
414
            if not dependency.is_defined
1✔
415
        ]
416

417
        if not undefined:
1✔
418
            return
1✔
419

420
        container_name = self.parent_name if self.parent_name else self.__class__.__name__
1✔
421
        undefined_names = [
1✔
422
            f"\"{dependency.parent_name if dependency.parent_name else dependency}\""
1✔
423
            for dependency in undefined
1✔
424
        ]
425
        raise errors.Error(
1✔
426
            f"Container \"{container_name}\" has undefined dependencies: "
1✔
427
            f"{', '.join(undefined_names)}",
1✔
428
        )
429

430
    def from_schema(self, schema):
1✔
431
        """Build container providers from schema."""
432
        from .schema import build_schema
1✔
433
        for name, provider in build_schema(schema).items():
1✔
434
            self.set_provider(name, provider)
1✔
435

436
    def from_yaml_schema(self, filepath, loader=None):
1✔
437
        """Build container providers from YAML schema.
438

439
        You can specify type of loader as a second argument. By default, method
440
        uses ``SafeLoader``.
441
        """
442
        if yaml is None:
1✔
443
            raise errors.Error(
1✔
444
                "Unable to load yaml schema - PyYAML is not installed. "
445
                "Install PyYAML or install Dependency Injector with yaml extras: "
446
                "\"pip install dependency-injector[yaml]\""
447
            )
448

449
        if loader is None:
1✔
450
            loader = yaml.SafeLoader
1✔
451

452
        with open(filepath) as file:
1✔
453
            schema = yaml.load(file, loader)
1✔
454

455
        self.from_schema(schema)
1✔
456

457
    def from_json_schema(self, filepath):
1✔
458
        """Build container providers from JSON schema."""
459
        with open(filepath) as file:
1✔
460
            schema = json.load(file)
1✔
461
        self.from_schema(schema)
1✔
462

463
    def resolve_provider_name(self, provider):
1✔
464
        """Try to resolve provider name."""
465
        for provider_name, container_provider in self.providers.items():
1✔
466
            if container_provider is provider:
1✔
467
                return provider_name
1✔
468
        else:
469
            raise errors.Error(f"Can not resolve name for provider \"{provider}\"")
1✔
470

471
    @property
1✔
472
    def parent_name(self):
473
        """Return parent name."""
474
        if self.parent:
1✔
475
            return self.parent.parent_name
1✔
476

477
        if self.declarative_parent:
1✔
478
            return self.declarative_parent.__name__
1✔
479

480
        return None
1✔
481

482
    def assign_parent(self, parent):
1✔
483
        """Assign parent."""
484
        self.parent = parent
1✔
485

486

487
class DeclarativeContainerMetaClass(type):
1✔
488
    """Declarative inversion of control container meta class."""
489

490
    def __new__(type mcs, str class_name, tuple bases, dict attributes):
1✔
491
        """Declarative container class factory."""
492
        self = mcs.__fetch_self(attributes)
1✔
493
        if self is None:
1✔
494
            self = providers.Self()
1✔
495

496
        containers = {
1✔
497
            name: container
1✔
498
            for name, container in six.iteritems(attributes)
1✔
499
            if is_container(container)
1✔
500
        }
501

502
        cls_providers = {
1✔
503
            name: provider
1✔
504
            for name, provider in six.iteritems(attributes)
1✔
505
            if isinstance(provider, providers.Provider) and not isinstance(provider, providers.Self)
1✔
506
        }
507

508
        inherited_providers = {
1✔
509
            name: provider
1✔
510
            for base in bases
1✔
511
            if is_container(base) and base is not DynamicContainer
1✔
512
            for name, provider in six.iteritems(base.providers)
1✔
513
        }
514

515
        all_providers = {}
1✔
516
        all_providers.update(inherited_providers)
1✔
517
        all_providers.update(cls_providers)
1✔
518

519
        wiring_config = attributes.get("wiring_config")
1✔
520
        if wiring_config is None:
1✔
521
            wiring_config = WiringConfiguration()
1✔
522
        if wiring_config is not None and not isinstance(wiring_config, WiringConfiguration):
1✔
523
            raise errors.Error(
×
524
                "Wiring configuration should be an instance of WiringConfiguration, "
525
                "instead got {0}".format(wiring_config)
×
526
            )
527

528
        attributes["containers"] = containers
1✔
529
        attributes["inherited_providers"] = inherited_providers
1✔
530
        attributes["cls_providers"] = cls_providers
1✔
531
        attributes["providers"] = all_providers
1✔
532
        attributes["wiring_config"] = wiring_config
1✔
533

534
        cls = <type>type.__new__(mcs, class_name, bases, attributes)
1✔
535

536
        self.set_container(cls)
1✔
537
        cls.__self__ = self
1✔
538

539
        for provider in six.itervalues(cls.providers):
1✔
540
            _check_provider_type(cls, provider)
1✔
541

542
        for provider in six.itervalues(cls.cls_providers):
1✔
543
            if isinstance(provider, providers.CHILD_PROVIDERS):
1✔
544
                provider.assign_parent(cls)
1✔
545

546
        return cls
1✔
547

548
    def __setattr__(cls, name, value):
1✔
549
        """Set class attribute.
550

551
        If value of attribute is provider, it will be added into providers
552
        dictionary.
553

554
        :param name: Attribute name
555
        :type name: object
556

557
        :param value: Attribute value
558
        :type value: object
559

560
        :rtype: None
561
        """
562
        if isinstance(value, providers.Provider) and name != "__self__":
1✔
563
            _check_provider_type(cls, value)
1✔
564

565
            if isinstance(value, providers.CHILD_PROVIDERS):
1✔
566
                value.assign_parent(cls)
1✔
567

568
            cls.providers[name] = value
1✔
569
            cls.cls_providers[name] = value
1✔
570
        super(DeclarativeContainerMetaClass, cls).__setattr__(name, value)
1✔
571

572
    def __delattr__(cls, name):
1✔
573
        """Delete class attribute.
574

575
        If value of attribute is provider, it will be deleted from providers
576
        dictionary.
577

578
        :param name: Attribute name
579
        :type name: object
580

581
        :rtype: None
582
        """
583
        if name in cls.providers and name in cls.cls_providers:
1✔
584
            del cls.providers[name]
1✔
585
            del cls.cls_providers[name]
1✔
586
        super(DeclarativeContainerMetaClass, cls).__delattr__(name)
1✔
587

588
    @property
1✔
589
    def dependencies(cls):
590
        """Return dependency providers dictionary.
591

592
        Dependency providers can be both of :py:class:`dependency_injector.providers.Dependency` and
593
        :py:class:`dependency_injector.providers.DependenciesContainer`.
594

595
        :rtype:
596
            dict[str, :py:class:`dependency_injector.providers.Provider`]
597
        """
598
        return {
1✔
599
            name: provider
1✔
600
            for name, provider in cls.providers.items()
1✔
601
            if isinstance(provider, (providers.Dependency, providers.DependenciesContainer))
1✔
602
        }
603

604
    def traverse(cls, types=None):
1✔
605
        """Return providers traversal generator."""
606
        yield from providers.traverse(*cls.providers.values(), types=types)
1✔
607

608
    def resolve_provider_name(cls, provider):
1✔
609
        """Try to resolve provider name."""
610
        for provider_name, container_provider in cls.providers.items():
1✔
611
            if container_provider is provider:
1✔
612
                return provider_name
1✔
613
        else:
614
            raise errors.Error(f"Can not resolve name for provider \"{provider}\"")
1✔
615

616
    @property
1✔
617
    def parent_name(cls):
618
        """Return parent name."""
619
        return cls.__name__
1✔
620

621
    @staticmethod
1✔
622
    def __fetch_self(attributes):
623
        self = None
1✔
624
        alt_names = []
1✔
625

626
        for name, value in attributes.items():
1✔
627
            if not isinstance(value, providers.Self):
1✔
628
                continue
1✔
629

630
            if self is not None and value is not self:
1✔
631
                raise errors.Error("Container can have only one \"Self\" provider")
1✔
632

633
            if name != "__self__":
1✔
634
                alt_names.append(name)
1✔
635

636
            self = value
1✔
637

638
        if self:
1✔
639
            self.set_alt_names(alt_names)
1✔
640

641
        return self
1✔
642

643

644
@six.add_metaclass(DeclarativeContainerMetaClass)
1✔
645
class DeclarativeContainer(Container):
1✔
646
    """Declarative inversion of control container.
647

648
    .. code-block:: python
649

650
        class Services(DeclarativeContainer):
651
            auth = providers.Factory(AuthService)
652
            users = providers.Factory(UsersService,
653
                                      auth_service=auth)
654
    """
655

656
    __IS_CONTAINER__ = True
1✔
657

658
    provider_type = providers.Provider
1✔
659
    """Type of providers that could be placed in container.
660

661
    :type: type
662
    """
663

664
    instance_type = DynamicContainer
1✔
665
    """Type of container that is returned on instantiating declarative
666
    container.
667

668
    :type: type
669
    """
670

671
    containers = dict()
1✔
672
    """Read-only dictionary of all nested containers.
673

674
    :type: dict[str, :py:class:`DeclarativeContainer`]
675
    """
676

677
    providers = dict()
1✔
678
    """Read-only dictionary of all providers.
679

680
    :type: dict[str, :py:class:`dependency_injector.providers.Provider`]
681
    """
682

683
    wiring_config = WiringConfiguration()
1✔
684
    """Wiring configuration.
685

686
    :type: WiringConfiguration
687
    """
688

689
    auto_load_config = True
1✔
690
    """Automatically load configuration when the container is created.
691

692
    :type: bool
693
    """
694

695
    cls_providers = dict()
1✔
696
    """Read-only dictionary of current container providers.
697

698
    :type: dict[str, :py:class:`dependency_injector.providers.Provider`]
699
    """
700

701
    inherited_providers = dict()
1✔
702
    """Read-only dictionary of inherited providers.
703

704
    :type: dict[str, :py:class:`dependency_injector.providers.Provider`]
705
    """
706

707
    overridden = tuple()
1✔
708
    """Tuple of overriding containers.
709

710
    :type: tuple[:py:class:`DeclarativeContainer`]
711
    """
712

713
    __self__ = None
1✔
714
    """Provider that provides current container.
715

716
    :type: :py:class:`dependency_injector.providers.Provider`
717
    """
718

719
    def __new__(cls, **overriding_providers):
1✔
720
        """Constructor.
721

722
        :return: Dynamic container with copy of all providers.
723
        :rtype: :py:class:`DynamicContainer`
724
        """
725
        container = cls.instance_type()
1✔
726
        container.provider_type = cls.provider_type
1✔
727
        container.wiring_config = copy_module.deepcopy(cls.wiring_config)
1✔
728
        container.declarative_parent = cls
1✔
729

730
        copied_providers = providers.deepcopy({ **cls.providers, **{"@@self@@": cls.__self__}})
1✔
731
        copied_self = copied_providers.pop("@@self@@")
1✔
732
        copied_self.set_container(container)
1✔
733

734
        container.__self__ = copied_self
1✔
735
        for name in copied_self.alt_names:
1✔
736
            container.set_provider(name, copied_self)
1✔
737

738
        for name, provider in copied_providers.items():
1✔
739
            container.set_provider(name, provider)
1✔
740

741
        if cls.auto_load_config:
1✔
742
            container.load_config()
1✔
743

744
        container.override_providers(**overriding_providers)
1✔
745
        container.apply_container_providers_overridings()
1✔
746

747
        if container.is_auto_wiring_enabled():
1✔
748
            container.wire()
1✔
749

750
        return container
1✔
751

752
    @classmethod
1✔
753
    def override(cls, object overriding):
754
        """Override current container by overriding container.
755

756
        :param overriding: Overriding container.
757
        :type overriding: :py:class:`DeclarativeContainer`
758

759
        :raise: :py:exc:`dependency_injector.errors.Error` if trying to
760
                override container by itself or its subclasses
761

762
        :rtype: None
763
        """
764
        if issubclass(cls, overriding):
1✔
765
            raise errors.Error("Container {0} could not be overridden "
1✔
766
                               "with itself or its subclasses".format(cls))
1✔
767

768
        cls.overridden += (overriding,)
1✔
769

770
        for name, provider in six.iteritems(overriding.cls_providers):
1✔
771
            try:
1✔
772
                getattr(cls, name).override(provider)
1✔
773
            except AttributeError:
1✔
774
                pass
775

776
    @classmethod
1✔
777
    def reset_last_overriding(cls):
778
        """Reset last overriding provider for each container providers.
779

780
        :rtype: None
781
        """
782
        if not cls.overridden:
1✔
783
            raise errors.Error("Container {0} is not overridden".format(cls))
1✔
784

785
        cls.overridden = cls.overridden[:-1]
1✔
786

787
        for provider in six.itervalues(cls.providers):
1✔
788
            provider.reset_last_overriding()
1✔
789

790
    @classmethod
1✔
791
    def reset_override(cls):
792
        """Reset all overridings for each container providers.
793

794
        :rtype: None
795
        """
796
        cls.overridden = tuple()
1✔
797

798
        for provider in six.itervalues(cls.providers):
1✔
799
            provider.reset_override()
1✔
800

801

802
class SingletonResetContext:
1✔
803

804
    def __init__(self, container):
1✔
805
        self._container = container
1✔
806

807
    def __enter__(self):
1✔
808
        return self._container
1✔
809

810
    def __exit__(self, *_):
1✔
811
        self._container.reset_singletons()
1✔
812

813

814

815
class ProvidersOverridingContext:
1✔
816

817
    def __init__(self, container, overridden_providers):
1✔
818
        self._container = container
1✔
819
        self._overridden_providers = overridden_providers
1✔
820

821
    def __enter__(self):
1✔
822
        return self._container
1✔
823

824
    def __exit__(self, *_):
1✔
825
        for provider in self._overridden_providers:
1✔
826
            provider.reset_last_overriding()
1✔
827

828

829
def override(object container):
1✔
830
    """:py:class:`DeclarativeContainer` overriding decorator.
831

832
    :param container: Container that should be overridden by decorated
833
                      container.
834
    :type container: :py:class:`DeclarativeContainer`
835

836
    :return: Declarative container overriding decorator.
837
    :rtype: callable(:py:class:`DeclarativeContainer`)
838
    """
839
    def _decorator(object overriding_container):
1✔
840
        """Overriding decorator."""
841
        container.override(overriding_container)
1✔
842
        return overriding_container
1✔
843
    return _decorator
1✔
844

845

846
def copy(object base_container):
1✔
847
    """:py:class:`DeclarativeContainer` copying decorator.
848

849
    This decorator copies all providers from provided container to decorated one.
850
    If one of the decorated container providers matches to source container
851
    providers by name, it would be replaced by reference.
852

853
    :param base_container: Container that should be copied by decorated container.
854
    :type base_container: :py:class:`DeclarativeContainer`
855

856
    :return: Declarative container copying decorator.
857
    :rtype: callable(:py:class:`DeclarativeContainer`)
858
    """
859
    def _get_memo_for_matching_names(new_providers, base_providers):
1✔
860
        memo = {}
1✔
861
        for new_provider_name, new_provider in six.iteritems(new_providers):
1✔
862
            if new_provider_name not in base_providers:
1✔
863
                continue
1✔
864
            source_provider = base_providers[new_provider_name]
1✔
865
            memo[id(source_provider)] = new_provider
1✔
866

867
            if hasattr(new_provider, "providers") and hasattr(source_provider, "providers"):
1✔
868
                sub_memo = _get_memo_for_matching_names(new_provider.providers, source_provider.providers)
1✔
869
                memo.update(sub_memo)
1✔
870
        return memo
1✔
871

872
    def _decorator(new_container):
1✔
873
        memo = {}
1✔
874
        memo.update(_get_memo_for_matching_names(new_container.cls_providers, base_container.providers))
1✔
875

876
        new_providers = {}
1✔
877
        new_providers.update(providers.deepcopy(base_container.providers, memo))
1✔
878
        new_providers.update(providers.deepcopy(new_container.cls_providers, memo))
1✔
879

880
        for name, provider in six.iteritems(new_providers):
1✔
881
            setattr(new_container, name, provider)
1✔
882
        return new_container
1✔
883

884
    return _decorator
1✔
885

886

887
cpdef bint is_container(object instance):
1✔
888
    """Check if instance is container instance.
889

890
    :param instance: Instance to be checked.
891
    :type instance: object
892

893
    :rtype: bool
894
    """
895
    return getattr(instance, "__IS_CONTAINER__", False) is True
1✔
896

897

898
cpdef object _check_provider_type(object container, object provider):
1✔
899
    if not isinstance(provider, container.provider_type):
1✔
900
        raise errors.Error("{0} can contain only {1} "
1✔
901
                           "instances".format(container, container.provider_type))
1✔
902

903

904
cpdef bint _any_relative_string_imports_in(object modules):
1✔
905
    for module in modules:
1✔
906
        if not isinstance(module, str):
1✔
907
            continue
1✔
908
        if module.startswith("."):
1✔
909
            return True
1✔
910
    else:
911
        return False
1✔
912

913

914
cpdef list _resolve_string_imports(object modules, object from_package):
1✔
915
    return [
1✔
916
        importlib.import_module(module, from_package) if isinstance(module, str) else module
1✔
917
        for module in modules
1✔
918
    ]
919

920

921
cpdef object _resolve_calling_package_name():
1✔
922
    stack = inspect.stack()
1✔
923
    pre_last_frame = stack[0]
1✔
924
    module = inspect.getmodule(pre_last_frame[0])
1✔
925
    return module.__package__
1✔
926

927

928
cpdef object _resolve_package_name_from_cls(cls):
1✔
929
    module = importlib.import_module(cls.__module__)
1✔
930
    return module.__package__
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc