diff --git a/021-conical-continued-again/magnum_opus/.gitignore b/021-conical-continued-again/magnum_opus/.gitignore new file mode 100644 index 0000000..9fb668e --- /dev/null +++ b/021-conical-continued-again/magnum_opus/.gitignore @@ -0,0 +1,3 @@ +*.egg-info +.tox +Pipfile diff --git a/021-conical-continued-again/magnum_opus/Dockerfile b/021-conical-continued-again/magnum_opus/Dockerfile new file mode 100644 index 0000000..03a8d6e --- /dev/null +++ b/021-conical-continued-again/magnum_opus/Dockerfile @@ -0,0 +1,24 @@ +FROM python:3-alpine + +RUN addgroup -S user && adduser user -S -G user + +WORKDIR /home/user/ + +COPY requirements.txt . +COPY gunicorn_config.py . +COPY setup.py . +COPY setup.cfg . +COPY init_entrypoint.sh / + +RUN pip install gunicorn +RUN pip install -r requirements.txt + +USER user + +EXPOSE 5000 + +ENTRYPOINT [] + +CMD gunicorn --config ./gunicorn_config.py magnumopus.index:app + +COPY magnumopus magnumopus diff --git a/021-conical-continued-again/magnum_opus/MANIFEST.in b/021-conical-continued-again/magnum_opus/MANIFEST.in new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/MANIFEST.in @@ -0,0 +1 @@ + diff --git a/021-conical-continued-again/magnum_opus/README.md b/021-conical-continued-again/magnum_opus/README.md new file mode 100644 index 0000000..b87be82 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/README.md @@ -0,0 +1,5 @@ +Magnum Opus +=========== + +This recipe maker +and averaged over repeated attempts, returning an average round trip time. diff --git a/021-conical-continued-again/magnum_opus/RULES.md b/021-conical-continued-again/magnum_opus/RULES.md new file mode 100644 index 0000000..4438311 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/RULES.md @@ -0,0 +1,9 @@ +* One unit of each of the substances Mercury, Salt and Sulphur are mixed, using my "Alembic" (mixing pot), giving one unit of another substance, Gloop +* Any attempt to mix anything other than those three substances, gives Sludge, another substance +* Substances can undergo several Processes in my Alembic - they can be Cooked, Washed, Pickled or Fermented +* If Gloop is Cooked, Washed, Pickled and Fermented, in that order, it is the Philosopher's Stone (panacea and cure of all ills) +[* To process a Substance, at least one unit must be in my Pantry, including Gloop - even when freshly processed/created, it must be stored there before re-use (to cool)] + +Final rule: +GROUP 1: When I process a substance, using any process, it becomes a different substance +GROUP 2: When I process a substance, its state changes but is essentially the same substance (NB: mixing is not a process) diff --git a/021-conical-continued-again/magnum_opus/docker-compose.yml b/021-conical-continued-again/magnum_opus/docker-compose.yml new file mode 100644 index 0000000..b5b9962 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/docker-compose.yml @@ -0,0 +1,10 @@ +version: "3" +services: + web: + build: . + environment: + DATABASE_URI: 'sqlite:////docker/storage/storage.db' + volumes: + - ./docker:/docker + ports: + - 5000:5000 diff --git a/021-conical-continued-again/magnum_opus/docker/storage/storage.db b/021-conical-continued-again/magnum_opus/docker/storage/storage.db new file mode 100644 index 0000000..1ca583a Binary files /dev/null and b/021-conical-continued-again/magnum_opus/docker/storage/storage.db differ diff --git a/021-conical-continued-again/magnum_opus/gunicorn_config.py b/021-conical-continued-again/magnum_opus/gunicorn_config.py new file mode 100644 index 0000000..29db9d9 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/gunicorn_config.py @@ -0,0 +1,5 @@ +port = '5000' +bind = "0.0.0.0:%s" % port +workers = 1 +timeout = 600 +reload = False diff --git a/021-conical-continued-again/magnum_opus/init_containers.sh b/021-conical-continued-again/magnum_opus/init_containers.sh new file mode 100755 index 0000000..0a64c94 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/init_containers.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +mkdir -p docker/storage + +docker-compose run --user root web /init_entrypoint.sh +docker-compose run web python3 -m magnumopus.initialize diff --git a/021-conical-continued-again/magnum_opus/init_entrypoint.sh b/021-conical-continued-again/magnum_opus/init_entrypoint.sh new file mode 100755 index 0000000..8366386 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/init_entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +chown -R user:user /docker/storage diff --git a/021-conical-continued-again/magnum_opus/magnumopus/__init__.py b/021-conical-continued-again/magnum_opus/magnumopus/__init__.py new file mode 100644 index 0000000..20817fc --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/__init__.py @@ -0,0 +1,17 @@ +from flask import Flask + +def create_app(): + from . import models, resources, schemas, logger + + app = Flask(__name__) + + # This could be used to separate by environment + app.config.from_object('magnumopus.config.Config') + + # This helps avoid cyclic dependencies + logger.init_app(app) + models.init_app(app) + resources.init_app(app) + schemas.init_app(app) + + return app diff --git a/021-conical-continued-again/magnum_opus/magnumopus/config.py b/021-conical-continued-again/magnum_opus/magnumopus/config.py new file mode 100644 index 0000000..dc9202e --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/config.py @@ -0,0 +1,5 @@ +import os + +class Config: + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI', 'sqlite:////tmp/test.db') + SQLALCHEMY_TRACK_MODIFICATIONS = False diff --git a/021-conical-continued-again/magnum_opus/magnumopus/index.py b/021-conical-continued-again/magnum_opus/magnumopus/index.py new file mode 100644 index 0000000..183c186 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/index.py @@ -0,0 +1,3 @@ +from . import create_app + +app = create_app() diff --git a/021-conical-continued-again/magnum_opus/magnumopus/initialize.py b/021-conical-continued-again/magnum_opus/magnumopus/initialize.py new file mode 100644 index 0000000..b251d32 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/initialize.py @@ -0,0 +1,9 @@ +from . import create_app +from .models import db + +if __name__ == "__main__": + # There are nicer ways around this, but this keeps it clear for an example + app = create_app() + + with app.app_context(): + db.create_all() diff --git a/021-conical-continued-again/magnum_opus/magnumopus/logger.py b/021-conical-continued-again/magnum_opus/magnumopus/logger.py new file mode 100644 index 0000000..9b7f97a --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/logger.py @@ -0,0 +1,5 @@ +import logging + +def init_app(app): + app.logger.addHandler(logging.StreamHandler()) + app.logger.setLevel(logging.INFO) diff --git a/021-conical-continued-again/magnum_opus/magnumopus/models/__init__.py b/021-conical-continued-again/magnum_opus/magnumopus/models/__init__.py new file mode 100644 index 0000000..e923302 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/models/__init__.py @@ -0,0 +1,4 @@ +from .base import db + +def init_app(app): + db.init_app(app) diff --git a/021-conical-continued-again/magnum_opus/magnumopus/models/base.py b/021-conical-continued-again/magnum_opus/magnumopus/models/base.py new file mode 100644 index 0000000..f0b13d6 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/models/base.py @@ -0,0 +1,3 @@ +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() diff --git a/021-conical-continued-again/magnum_opus/magnumopus/models/substance.py b/021-conical-continued-again/magnum_opus/magnumopus/models/substance.py new file mode 100644 index 0000000..58e821e --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/models/substance.py @@ -0,0 +1,34 @@ +from . import db +from sqlalchemy_utils.types.scalar_list import ScalarListType + +class SubstanceMustBeFreshToProcessException(Exception): + pass + +class Substance(db.Model): + __tablename__ = 'substances' + + id = db.Column(db.Integer, primary_key=True) + nature = db.Column(db.String(32), default='Unknown') + state = db.Column(ScalarListType()) + + def __init__(self, nature='Unknown'): + self.state = [] + self.nature = nature + + super(Substance, self).__init__() + + def _process(self, process_name): + self.state.append(process_name) + return self + + def cook(self): + return self._process('cooked') + + def pickle(self): + return self._process('pickled') + + def ferment(self): + return self._process('fermented') + + def wash(self): + return self._process('washed') diff --git a/021-conical-continued-again/magnum_opus/magnumopus/repositories/__init__.py b/021-conical-continued-again/magnum_opus/magnumopus/repositories/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/021-conical-continued-again/magnum_opus/magnumopus/repositories/pantry.py b/021-conical-continued-again/magnum_opus/magnumopus/repositories/pantry.py new file mode 100644 index 0000000..2e47a8a --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/repositories/pantry.py @@ -0,0 +1,17 @@ +class Pantry: + _cupboard = [] + + def __init__(self): + pass + + def add_substance(self, substance): + self._cupboard.append(substance) + + def find_substances_by_nature(self, nature): + return [substance for substance in self._cupboard if substance.nature == nature] + + def count_all_substances(self): + return len(self._cupboard) + + def commit(self): + pass diff --git a/021-conical-continued-again/magnum_opus/magnumopus/repositories/sqlalchemy_pantry.py b/021-conical-continued-again/magnum_opus/magnumopus/repositories/sqlalchemy_pantry.py new file mode 100644 index 0000000..f3c2173 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/repositories/sqlalchemy_pantry.py @@ -0,0 +1,24 @@ +from ..models.substance import Substance +from ..models import db + +class SQLAlchemyPantry: + def __init__(self): + self._db = db + + # A more involved solution would open and close the pantry... like + # a cupboard door, or a Unit of Work + + # Note how we're committing too frequently? + def add_substance(self, substance): + self._db.session.add(substance) + return substance + + def find_substances_by_nature(self, nature): + substances = Substance.query.filter_by(nature=nature).all() + return substances + + def count_all_substances(self): + return Substance.count() + + def commit(self): + self._db.session.commit() diff --git a/021-conical-continued-again/magnum_opus/magnumopus/resources/__init__.py b/021-conical-continued-again/magnum_opus/magnumopus/resources/__init__.py new file mode 100644 index 0000000..85683b9 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/resources/__init__.py @@ -0,0 +1,8 @@ +from flask_restful import Api +from . import substance +from . import alembic_instruction + +def init_app(app): + api = Api(app) + substance.init_app(app, api) + alembic_instruction.init_app(app, api) diff --git a/021-conical-continued-again/magnum_opus/magnumopus/resources/alembic_instruction.py b/021-conical-continued-again/magnum_opus/magnumopus/resources/alembic_instruction.py new file mode 100644 index 0000000..6af7113 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/resources/alembic_instruction.py @@ -0,0 +1,52 @@ +from flask_restful import Resource, reqparse +from ..repositories.pantry import Pantry +from ..repositories.sqlalchemy_pantry import SQLAlchemyPantry +from ..models.substance import Substance +from ..schemas.substance_schema import SubstanceSchema +from ..services.alembic_instruction_handler import AlembicInstructionHandler, AlembicInstruction + +parser = reqparse.RequestParser() +parser.add_argument('instruction_type') +parser.add_argument('action') +parser.add_argument('natures') + +substance_schema = SubstanceSchema() + +class AlembicInstructionResource(Resource): + def get(self): + """This should return past requests/commands.""" + pass + + def post(self): + """ + Add an instruction for the alembic. + + Note that POST is _not_ assumed to be idempotent, unlike PUT + """ + + args = parser.parse_args() + instruction_type = args['instruction_type'] + + pantry = SQLAlchemyPantry() + + instruction_handler = AlembicInstructionHandler() + + # This could do with deserialization... + instruction = AlembicInstruction( + instruction_type=args.instruction_type, + natures=args.natures.split(','), + action=args.action + ) + + # Crude start at DI... see flask-injector + result = instruction_handler.handle(instruction, pantry) + + pantry.add_substance(result) + + pantry.commit() + + return substance_schema.dump(result) + + +def init_app(app, api): + api.add_resource(AlembicInstructionResource, '/alembic_instruction') diff --git a/021-conical-continued-again/magnum_opus/magnumopus/resources/substance.py b/021-conical-continued-again/magnum_opus/magnumopus/resources/substance.py new file mode 100644 index 0000000..a07c24e --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/resources/substance.py @@ -0,0 +1,44 @@ +from flask_restful import Resource, reqparse +from ..repositories.pantry import Pantry +from ..repositories.sqlalchemy_pantry import SQLAlchemyPantry +from ..models import db +from ..models.substance import Substance +from ..schemas.substance_schema import SubstanceSchema + +parser = reqparse.RequestParser() +parser.add_argument('nature') + +substance_schema = SubstanceSchema() +substances_schema = SubstanceSchema(many=True) + +pantry_cls = SQLAlchemyPantry + + +class SubstanceResource(Resource): + def get(self): + args = parser.parse_args() + nature = args['nature'] + + pantry = pantry_cls() + + substances = pantry.find_substances_by_nature(nature) + + return substances_schema.dump(substances) + + def post(self): + args = parser.parse_args() + nature = args['nature'] + + pantry = pantry_cls() + + substance = Substance(nature=nature) + + pantry.add_substance(substance) + + pantry.commit() + + return substance_schema.dump(substance) + + +def init_app(app, api): + api.add_resource(SubstanceResource, '/substance') diff --git a/021-conical-continued-again/magnum_opus/magnumopus/schemas/__init__.py b/021-conical-continued-again/magnum_opus/magnumopus/schemas/__init__.py new file mode 100644 index 0000000..34395e3 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/schemas/__init__.py @@ -0,0 +1,6 @@ +from flask_marshmallow import Marshmallow + +ma = Marshmallow() + +def init_app(app): + ma.init_app(app) diff --git a/021-conical-continued-again/magnum_opus/magnumopus/schemas/substance_schema.py b/021-conical-continued-again/magnum_opus/magnumopus/schemas/substance_schema.py new file mode 100644 index 0000000..6484e98 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/schemas/substance_schema.py @@ -0,0 +1,18 @@ +from marshmallow import fields + +from . import ma + +from ..models.substance import Substance +from ..services.assessor import assess_whether_substance_is_philosophers_stone + +class SubstanceSchema(ma.SQLAlchemySchema): + is_philosophers_stone = fields.Function( + assess_whether_substance_is_philosophers_stone + ) + + class Meta: + model = Substance + fields = ('id', 'nature', 'is_philosophers_stone', 'state') + + id = ma.auto_field() + nature = ma.auto_field() diff --git a/021-conical-continued-again/magnum_opus/magnumopus/services/__init__.py b/021-conical-continued-again/magnum_opus/magnumopus/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/021-conical-continued-again/magnum_opus/magnumopus/services/alembic.py b/021-conical-continued-again/magnum_opus/magnumopus/services/alembic.py new file mode 100644 index 0000000..5fc05b2 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/services/alembic.py @@ -0,0 +1,51 @@ +from ..models.substance import Substance + +class NotEnoughSubstancesToMixException(Exception): + pass + +class UnknownProcessException(Exception): + pass + + +MIXTURES = { + ('Mercury', 'Salt', 'Sulphur'): 'Gloop' +} + + +class Alembic: + _nature_of_unknown_mixture = 'Sludge' + + @staticmethod + def _produce(nature): + return Substance(nature=nature) + + def mix(self, *substances): + if len(substances) < 2: + raise NotEnoughSubstancesToMixException() + + constituents = [substance.nature for substance in substances] + + # This gives us a canonical, ordered way of expressing our + # constituents that we can use as a recipe look-up + ingredient_list = tuple(sorted(constituents)) + + try: + nature = MIXTURES[ingredient_list] + except KeyError: + nature = self._nature_of_unknown_mixture + + return self._produce(nature) + + def process(self, process_name, substance): + if process_name == 'ferment': + result = substance.ferment() + elif process_name == 'cook': + result = substance.cook() + elif process_name == 'wash': + result = substance.wash() + elif process_name == 'pickle': + result = substance.pickle() + else: + raise UnknownProcessException() + + return result diff --git a/021-conical-continued-again/magnum_opus/magnumopus/services/alembic_instruction_handler.py b/021-conical-continued-again/magnum_opus/magnumopus/services/alembic_instruction_handler.py new file mode 100644 index 0000000..556bbe2 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/services/alembic_instruction_handler.py @@ -0,0 +1,31 @@ +from dataclasses import dataclass + +from .alembic import Alembic +from ..repositories.pantry import Pantry + +@dataclass +class AlembicInstruction: + instruction_type: str + natures: list + action: str = '' + +class AlembicInstructionHandler: + def handle(self, instruction: AlembicInstruction, pantry: Pantry): + natures = instruction.natures + action = instruction.action + instruction_type = instruction.instruction_type + + # Clearly need some validation here! + substances = [pantry.find_substances_by_nature(nature)[0] for nature in natures] + + alembic = Alembic() + + if instruction_type == 'mix': + result = alembic.mix(*substances) + elif instruction_type == 'process': + result = alembic.process(action, substances[0]) + else: + pass + # a sensible error + + return result diff --git a/021-conical-continued-again/magnum_opus/magnumopus/services/assessor.py b/021-conical-continued-again/magnum_opus/magnumopus/services/assessor.py new file mode 100644 index 0000000..94d564d --- /dev/null +++ b/021-conical-continued-again/magnum_opus/magnumopus/services/assessor.py @@ -0,0 +1,2 @@ +def assess_whether_substance_is_philosophers_stone(substance): + return substance.nature == 'Gloop' and substance.state == ['cooked', 'washed', 'pickled', 'fermented'] diff --git a/021-conical-continued-again/magnum_opus/requirements.txt b/021-conical-continued-again/magnum_opus/requirements.txt new file mode 100644 index 0000000..046ee33 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/requirements.txt @@ -0,0 +1,7 @@ +appdirs +flask +flask-restful +flask-marshmallow +flask-sqlalchemy +marshmallow-sqlalchemy +sqlalchemy-utils diff --git a/021-conical-continued-again/magnum_opus/setup.cfg b/021-conical-continued-again/magnum_opus/setup.cfg new file mode 100644 index 0000000..503b042 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/setup.cfg @@ -0,0 +1,25 @@ +[metadata] +name = magnumopus +version = 0.0.1 +author = Phil Weir +author_email = phil.weir@flaxandteal.co.uk +license = GPL +description = Service for cooking up a philosopher's stone +long-description = file:README.md + +[options] +include_package_data = True +packages = find: +python_requires = >=3.6 +install_requires = + appdirs + flask-restful + flask-marshmallow + flask-sqlalchemy + sqlalchemy-utils + marshmallow-sqlalchemy + flask + +[options.packages.find] +exclude = + tests diff --git a/021-conical-continued-again/magnum_opus/setup.py b/021-conical-continued-again/magnum_opus/setup.py new file mode 100644 index 0000000..1767837 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/setup.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +""" +Magnum Opus + +This tool performs alchemical reactions to create +the Philosopher's Stone. + +@author: Phil Weir +""" + +from setuptools import setup + +if __name__ == '__main__': + setup() diff --git a/021-conical-continued-again/magnum_opus/tests/test_alembic.py b/021-conical-continued-again/magnum_opus/tests/test_alembic.py new file mode 100644 index 0000000..cd67657 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/tests/test_alembic.py @@ -0,0 +1,81 @@ +import pytest + +from magnumopus.services.alembic import Alembic, NotEnoughSubstancesToMixException, UnknownProcessException +from magnumopus.models.substance import Substance + +def test_can_set_up_my_alembic(): + Alembic() + +def test_can_mix_multiple_substances_in_my_alembic(): + alembic = Alembic() + substance = [Substance() for _ in range(3)] + alembic.mix(*substance) + + substance = [Substance() for _ in range(6)] + alembic.mix(*substance) + +def test_cannot_mix_one_substance_in_my_alembic(): + alembic = Alembic() + substance = Substance() + + with pytest.raises(NotEnoughSubstancesToMixException): + alembic.mix(substance) + +def test_mixing_sulphur_salt_and_mercury_gives_gloop(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + + result = alembic.mix(sulphur, salt, mercury) + + assert result.nature == 'Gloop' + + result = alembic.mix(mercury, sulphur, salt) + + assert result.nature == 'Gloop' + +def test_mixing_other_recipes_gives_sludge(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + gloop = Substance(nature='Gloop') + + result = alembic.mix(sulphur, salt, mercury, sulphur) + + assert result.nature == 'Sludge' + + result = alembic.mix(salt, mercury) + + assert result.nature == 'Sludge' + + result = alembic.mix(gloop, salt, mercury) + + assert result.nature == 'Sludge' + +def test_can_process_substance(): + alembic = Alembic() + + substance = Substance() + result = alembic.process('cook', substance) + + substance = Substance() + cooked_substance = substance.cook() + + assert result.state == cooked_substance.state + + result = alembic.process('ferment', substance) + cooked_fermented_substance = cooked_substance.ferment() + + assert result.state == cooked_fermented_substance.state + +def test_cannot_perform_unknown_process(): + alembic = Alembic() + + substance = Substance() + + with pytest.raises(UnknownProcessException): + alembic.process('boil', substance) diff --git a/021-conical-continued-again/magnum_opus/tests/test_pantry.py b/021-conical-continued-again/magnum_opus/tests/test_pantry.py new file mode 100644 index 0000000..c968129 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/tests/test_pantry.py @@ -0,0 +1,22 @@ +from magnumopus.repositories.pantry import Pantry +from magnumopus.models.substance import Substance + +def test_can_add_to_pantry(): + pantry = Pantry() + + substance = Substance() + + pantry.add_substance(substance) + + assert pantry.count_all_substances() == 1 + +def test_can_retrieve_substance_from_pantry_by_nature(): + pantry = Pantry() + + substance = Substance(nature='Mercury') + + pantry.add_substance(substance) + + mercury = pantry.find_substances_by_nature('Mercury')[0] + + assert mercury.nature == 'Mercury' diff --git a/021-conical-continued-again/magnum_opus/tests/test_substance.py b/021-conical-continued-again/magnum_opus/tests/test_substance.py new file mode 100644 index 0000000..d00a6f7 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/tests/test_substance.py @@ -0,0 +1,49 @@ +from magnumopus.models.substance import Substance + +def test_can_cook_substance(): + substance = Substance() + + result = substance.cook() + + assert substance.state == ['cooked'] + +def test_can_wash_substance(): + substance = Substance() + + result = substance.wash() + + assert result.state == ['washed'] + +def test_can_pickle_substance(): + substance = Substance() + + result = substance.pickle() + + assert result.state == ['pickled'] + +def test_can_ferment_substance(): + substance = Substance() + + result = substance.ferment() + + assert substance.state == ['fermented'] + +def test_can_cook_and_ferment_substance(): + substance = Substance() + + result = substance.cook() + result = result.ferment() + + assert substance.state == ['cooked', 'fermented'] + +def test_the_order_of_processes_applied_to_a_substance_matters(): + substance1 = Substance() + result1 = substance1.cook() + result1 = result1.ferment() + + substance2 = Substance() + result2 = substance2.ferment() + result2 = result2.cook() + + assert result1.state != result2.state + assert result1.state == result2.state[::-1] diff --git a/021-conical-continued-again/magnum_opus/tox.ini b/021-conical-continued-again/magnum_opus/tox.ini new file mode 100644 index 0000000..d815853 --- /dev/null +++ b/021-conical-continued-again/magnum_opus/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist = py38 + +[testenv] +deps = pytest +commands = pytest diff --git a/021-conical-continued/magnum_opus/.gitignore b/021-conical-continued/magnum_opus/.gitignore new file mode 100644 index 0000000..9fb668e --- /dev/null +++ b/021-conical-continued/magnum_opus/.gitignore @@ -0,0 +1,3 @@ +*.egg-info +.tox +Pipfile diff --git a/021-conical-continued/magnum_opus/Dockerfile b/021-conical-continued/magnum_opus/Dockerfile new file mode 100644 index 0000000..e8b07e3 --- /dev/null +++ b/021-conical-continued/magnum_opus/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3-alpine + +RUN addgroup -S user && adduser user -S -G user + +WORKDIR /home/user/ + +COPY requirements.txt . +COPY gunicorn_config.py . +COPY setup.py . +COPY setup.cfg . + +RUN pip install gunicorn +RUN pip install -r requirements.txt + +USER user + +EXPOSE 5000 + +ENTRYPOINT [] + +CMD gunicorn --config ./gunicorn_config.py magnumopus.index:app + +COPY magnumopus magnumopus diff --git a/021-conical-continued/magnum_opus/MANIFEST.in b/021-conical-continued/magnum_opus/MANIFEST.in new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/021-conical-continued/magnum_opus/MANIFEST.in @@ -0,0 +1 @@ + diff --git a/021-conical-continued/magnum_opus/README.md b/021-conical-continued/magnum_opus/README.md new file mode 100644 index 0000000..b87be82 --- /dev/null +++ b/021-conical-continued/magnum_opus/README.md @@ -0,0 +1,5 @@ +Magnum Opus +=========== + +This recipe maker +and averaged over repeated attempts, returning an average round trip time. diff --git a/021-conical-continued/magnum_opus/RULES.md b/021-conical-continued/magnum_opus/RULES.md new file mode 100644 index 0000000..4438311 --- /dev/null +++ b/021-conical-continued/magnum_opus/RULES.md @@ -0,0 +1,9 @@ +* One unit of each of the substances Mercury, Salt and Sulphur are mixed, using my "Alembic" (mixing pot), giving one unit of another substance, Gloop +* Any attempt to mix anything other than those three substances, gives Sludge, another substance +* Substances can undergo several Processes in my Alembic - they can be Cooked, Washed, Pickled or Fermented +* If Gloop is Cooked, Washed, Pickled and Fermented, in that order, it is the Philosopher's Stone (panacea and cure of all ills) +[* To process a Substance, at least one unit must be in my Pantry, including Gloop - even when freshly processed/created, it must be stored there before re-use (to cool)] + +Final rule: +GROUP 1: When I process a substance, using any process, it becomes a different substance +GROUP 2: When I process a substance, its state changes but is essentially the same substance (NB: mixing is not a process) diff --git a/021-conical-continued/magnum_opus/docker-compose.yml b/021-conical-continued/magnum_opus/docker-compose.yml new file mode 100644 index 0000000..a234fe9 --- /dev/null +++ b/021-conical-continued/magnum_opus/docker-compose.yml @@ -0,0 +1,6 @@ +version: "3" +services: + web: + build: . + ports: + - 5000:5000 diff --git a/021-conical-continued/magnum_opus/gunicorn_config.py b/021-conical-continued/magnum_opus/gunicorn_config.py new file mode 100644 index 0000000..29db9d9 --- /dev/null +++ b/021-conical-continued/magnum_opus/gunicorn_config.py @@ -0,0 +1,5 @@ +port = '5000' +bind = "0.0.0.0:%s" % port +workers = 1 +timeout = 600 +reload = False diff --git a/021-conical-continued/magnum_opus/magnumopus/__init__.py b/021-conical-continued/magnum_opus/magnumopus/__init__.py new file mode 100644 index 0000000..2a3a1fb --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/__init__.py @@ -0,0 +1,14 @@ +from flask import Flask + +def create_app(): + from . import models, resources, schemas, logger + + app = Flask(__name__) + + # This helps avoid cyclic dependencies + logger.init_app(app) + models.init_app(app) + resources.init_app(app) + schemas.init_app(app) + + return app diff --git a/021-conical-continued/magnum_opus/magnumopus/index.py b/021-conical-continued/magnum_opus/magnumopus/index.py new file mode 100644 index 0000000..183c186 --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/index.py @@ -0,0 +1,3 @@ +from . import create_app + +app = create_app() diff --git a/021-conical-continued/magnum_opus/magnumopus/logger.py b/021-conical-continued/magnum_opus/magnumopus/logger.py new file mode 100644 index 0000000..9b7f97a --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/logger.py @@ -0,0 +1,5 @@ +import logging + +def init_app(app): + app.logger.addHandler(logging.StreamHandler()) + app.logger.setLevel(logging.INFO) diff --git a/021-conical-continued/magnum_opus/magnumopus/models/__init__.py b/021-conical-continued/magnum_opus/magnumopus/models/__init__.py new file mode 100644 index 0000000..2e94a1e --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/models/__init__.py @@ -0,0 +1,5 @@ +from .base import db + +def init_app(app): + app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' + db.init_app(app) diff --git a/021-conical-continued/magnum_opus/magnumopus/models/base.py b/021-conical-continued/magnum_opus/magnumopus/models/base.py new file mode 100644 index 0000000..f0b13d6 --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/models/base.py @@ -0,0 +1,3 @@ +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() diff --git a/021-conical-continued/magnum_opus/magnumopus/models/substance.py b/021-conical-continued/magnum_opus/magnumopus/models/substance.py new file mode 100644 index 0000000..828b4c5 --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/models/substance.py @@ -0,0 +1,23 @@ +class SubstanceMustBeFreshToProcessException(Exception): + pass + +class Substance: + def __init__(self, nature='Unknown'): + self.nature = nature + self.state = [] + + def _process(self, process_name): + self.state.append(process_name) + return self + + def cook(self): + return self._process('cooked') + + def pickle(self): + return self._process('pickled') + + def ferment(self): + return self._process('fermented') + + def wash(self): + return self._process('washed') diff --git a/021-conical-continued/magnum_opus/magnumopus/repositories/__init__.py b/021-conical-continued/magnum_opus/magnumopus/repositories/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/021-conical-continued/magnum_opus/magnumopus/repositories/pantry.py b/021-conical-continued/magnum_opus/magnumopus/repositories/pantry.py new file mode 100644 index 0000000..90ac0d9 --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/repositories/pantry.py @@ -0,0 +1,14 @@ +class Pantry: + _cupboard = [] + + def __init__(self): + pass + + def add_substance(self, substance): + self._cupboard.append(substance) + + def find_substances_by_nature(self, nature): + return [substance for substance in self._cupboard if substance.nature == nature] + + def count_all_substances(self): + return len(self._cupboard) diff --git a/021-conical-continued/magnum_opus/magnumopus/resources/__init__.py b/021-conical-continued/magnum_opus/magnumopus/resources/__init__.py new file mode 100644 index 0000000..85683b9 --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/resources/__init__.py @@ -0,0 +1,8 @@ +from flask_restful import Api +from . import substance +from . import alembic_instruction + +def init_app(app): + api = Api(app) + substance.init_app(app, api) + alembic_instruction.init_app(app, api) diff --git a/021-conical-continued/magnum_opus/magnumopus/resources/alembic_instruction.py b/021-conical-continued/magnum_opus/magnumopus/resources/alembic_instruction.py new file mode 100644 index 0000000..1843acf --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/resources/alembic_instruction.py @@ -0,0 +1,49 @@ +from flask_restful import Resource, reqparse +from ..repositories.pantry import Pantry +from ..models.substance import Substance +from ..schemas.substance_schema import SubstanceSchema +from ..services.alembic_instruction_handler import AlembicInstructionHandler, AlembicInstruction + +parser = reqparse.RequestParser() +parser.add_argument('instruction_type') +parser.add_argument('action') +parser.add_argument('natures') + +substance_schema = SubstanceSchema() + +class AlembicInstructionResource(Resource): + def get(self): + """This should return past requests/commands.""" + pass + + def post(self): + """ + Add an instruction for the alembic. + + Note that POST is _not_ assumed to be idempotent, unlike PUT + """ + + args = parser.parse_args() + instruction_type = args['instruction_type'] + + pantry = Pantry() + + instruction_handler = AlembicInstructionHandler() + + # This could do with deserialization... + instruction = AlembicInstruction( + instruction_type=args.instruction_type, + natures=args.natures.split(','), + action=args.action + ) + + # Crude start at DI... see flask-injector + result = instruction_handler.handle(instruction, pantry) + + pantry.add_substance(result) + + return substance_schema.dump(result) + + +def init_app(app, api): + api.add_resource(AlembicInstructionResource, '/alembic_instruction') diff --git a/021-conical-continued/magnum_opus/magnumopus/resources/substance.py b/021-conical-continued/magnum_opus/magnumopus/resources/substance.py new file mode 100644 index 0000000..770dcac --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/resources/substance.py @@ -0,0 +1,37 @@ +from flask_restful import Resource, reqparse +from ..repositories.pantry import Pantry +from ..models.substance import Substance +from ..schemas.substance_schema import SubstanceSchema + +parser = reqparse.RequestParser() +parser.add_argument('nature') + +substance_schema = SubstanceSchema() +substances_schema = SubstanceSchema(many=True) + + +class SubstanceResource(Resource): + def get(self): + args = parser.parse_args() + nature = args['nature'] + pantry = Pantry() + + substances = pantry.find_substances_by_nature(nature) + + return substances_schema.dump(substances) + + def post(self): + args = parser.parse_args() + nature = args['nature'] + + pantry = Pantry() + + substance = Substance(nature=nature) + + pantry.add_substance(substance) + + return substance_schema.dump(substance) + + +def init_app(app, api): + api.add_resource(SubstanceResource, '/substance') diff --git a/021-conical-continued/magnum_opus/magnumopus/schemas/__init__.py b/021-conical-continued/magnum_opus/magnumopus/schemas/__init__.py new file mode 100644 index 0000000..34395e3 --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/schemas/__init__.py @@ -0,0 +1,6 @@ +from flask_marshmallow import Marshmallow + +ma = Marshmallow() + +def init_app(app): + ma.init_app(app) diff --git a/021-conical-continued/magnum_opus/magnumopus/schemas/substance_schema.py b/021-conical-continued/magnum_opus/magnumopus/schemas/substance_schema.py new file mode 100644 index 0000000..430e96c --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/schemas/substance_schema.py @@ -0,0 +1,13 @@ +from marshmallow import fields + +from . import ma + +from ..services.assessor import assess_whether_substance_is_philosophers_stone + +class SubstanceSchema(ma.Schema): + is_philosophers_stone = fields.Function( + assess_whether_substance_is_philosophers_stone + ) + + class Meta: + fields = ("nature", "is_philosophers_stone") diff --git a/021-conical-continued/magnum_opus/magnumopus/services/__init__.py b/021-conical-continued/magnum_opus/magnumopus/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/021-conical-continued/magnum_opus/magnumopus/services/alembic.py b/021-conical-continued/magnum_opus/magnumopus/services/alembic.py new file mode 100644 index 0000000..5fc05b2 --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/services/alembic.py @@ -0,0 +1,51 @@ +from ..models.substance import Substance + +class NotEnoughSubstancesToMixException(Exception): + pass + +class UnknownProcessException(Exception): + pass + + +MIXTURES = { + ('Mercury', 'Salt', 'Sulphur'): 'Gloop' +} + + +class Alembic: + _nature_of_unknown_mixture = 'Sludge' + + @staticmethod + def _produce(nature): + return Substance(nature=nature) + + def mix(self, *substances): + if len(substances) < 2: + raise NotEnoughSubstancesToMixException() + + constituents = [substance.nature for substance in substances] + + # This gives us a canonical, ordered way of expressing our + # constituents that we can use as a recipe look-up + ingredient_list = tuple(sorted(constituents)) + + try: + nature = MIXTURES[ingredient_list] + except KeyError: + nature = self._nature_of_unknown_mixture + + return self._produce(nature) + + def process(self, process_name, substance): + if process_name == 'ferment': + result = substance.ferment() + elif process_name == 'cook': + result = substance.cook() + elif process_name == 'wash': + result = substance.wash() + elif process_name == 'pickle': + result = substance.pickle() + else: + raise UnknownProcessException() + + return result diff --git a/021-conical-continued/magnum_opus/magnumopus/services/alembic_instruction_handler.py b/021-conical-continued/magnum_opus/magnumopus/services/alembic_instruction_handler.py new file mode 100644 index 0000000..556bbe2 --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/services/alembic_instruction_handler.py @@ -0,0 +1,31 @@ +from dataclasses import dataclass + +from .alembic import Alembic +from ..repositories.pantry import Pantry + +@dataclass +class AlembicInstruction: + instruction_type: str + natures: list + action: str = '' + +class AlembicInstructionHandler: + def handle(self, instruction: AlembicInstruction, pantry: Pantry): + natures = instruction.natures + action = instruction.action + instruction_type = instruction.instruction_type + + # Clearly need some validation here! + substances = [pantry.find_substances_by_nature(nature)[0] for nature in natures] + + alembic = Alembic() + + if instruction_type == 'mix': + result = alembic.mix(*substances) + elif instruction_type == 'process': + result = alembic.process(action, substances[0]) + else: + pass + # a sensible error + + return result diff --git a/021-conical-continued/magnum_opus/magnumopus/services/assessor.py b/021-conical-continued/magnum_opus/magnumopus/services/assessor.py new file mode 100644 index 0000000..94d564d --- /dev/null +++ b/021-conical-continued/magnum_opus/magnumopus/services/assessor.py @@ -0,0 +1,2 @@ +def assess_whether_substance_is_philosophers_stone(substance): + return substance.nature == 'Gloop' and substance.state == ['cooked', 'washed', 'pickled', 'fermented'] diff --git a/021-conical-continued/magnum_opus/requirements.txt b/021-conical-continued/magnum_opus/requirements.txt new file mode 100644 index 0000000..10bd0c2 --- /dev/null +++ b/021-conical-continued/magnum_opus/requirements.txt @@ -0,0 +1,5 @@ +appdirs +flask +flask-restful +flask-marshmallow +flask-sqlalchemy diff --git a/021-conical-continued/magnum_opus/setup.cfg b/021-conical-continued/magnum_opus/setup.cfg new file mode 100644 index 0000000..262547a --- /dev/null +++ b/021-conical-continued/magnum_opus/setup.cfg @@ -0,0 +1,23 @@ +[metadata] +name = magnumopus +version = 0.0.1 +author = Phil Weir +author_email = phil.weir@flaxandteal.co.uk +license = GPL +description = Service for cooking up a philosopher's stone +long-description = file:README.md + +[options] +include_package_data = True +packages = find: +python_requires = >=3.6 +install_requires = + appdirs + flask-restful + flask-marshmallow + flask-sqlalchemy + flask + +[options.packages.find] +exclude = + tests diff --git a/021-conical-continued/magnum_opus/setup.py b/021-conical-continued/magnum_opus/setup.py new file mode 100644 index 0000000..1767837 --- /dev/null +++ b/021-conical-continued/magnum_opus/setup.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +""" +Magnum Opus + +This tool performs alchemical reactions to create +the Philosopher's Stone. + +@author: Phil Weir +""" + +from setuptools import setup + +if __name__ == '__main__': + setup() diff --git a/021-conical-continued/magnum_opus/tests/test_alembic.py b/021-conical-continued/magnum_opus/tests/test_alembic.py new file mode 100644 index 0000000..cd67657 --- /dev/null +++ b/021-conical-continued/magnum_opus/tests/test_alembic.py @@ -0,0 +1,81 @@ +import pytest + +from magnumopus.services.alembic import Alembic, NotEnoughSubstancesToMixException, UnknownProcessException +from magnumopus.models.substance import Substance + +def test_can_set_up_my_alembic(): + Alembic() + +def test_can_mix_multiple_substances_in_my_alembic(): + alembic = Alembic() + substance = [Substance() for _ in range(3)] + alembic.mix(*substance) + + substance = [Substance() for _ in range(6)] + alembic.mix(*substance) + +def test_cannot_mix_one_substance_in_my_alembic(): + alembic = Alembic() + substance = Substance() + + with pytest.raises(NotEnoughSubstancesToMixException): + alembic.mix(substance) + +def test_mixing_sulphur_salt_and_mercury_gives_gloop(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + + result = alembic.mix(sulphur, salt, mercury) + + assert result.nature == 'Gloop' + + result = alembic.mix(mercury, sulphur, salt) + + assert result.nature == 'Gloop' + +def test_mixing_other_recipes_gives_sludge(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + gloop = Substance(nature='Gloop') + + result = alembic.mix(sulphur, salt, mercury, sulphur) + + assert result.nature == 'Sludge' + + result = alembic.mix(salt, mercury) + + assert result.nature == 'Sludge' + + result = alembic.mix(gloop, salt, mercury) + + assert result.nature == 'Sludge' + +def test_can_process_substance(): + alembic = Alembic() + + substance = Substance() + result = alembic.process('cook', substance) + + substance = Substance() + cooked_substance = substance.cook() + + assert result.state == cooked_substance.state + + result = alembic.process('ferment', substance) + cooked_fermented_substance = cooked_substance.ferment() + + assert result.state == cooked_fermented_substance.state + +def test_cannot_perform_unknown_process(): + alembic = Alembic() + + substance = Substance() + + with pytest.raises(UnknownProcessException): + alembic.process('boil', substance) diff --git a/021-conical-continued/magnum_opus/tests/test_pantry.py b/021-conical-continued/magnum_opus/tests/test_pantry.py new file mode 100644 index 0000000..c968129 --- /dev/null +++ b/021-conical-continued/magnum_opus/tests/test_pantry.py @@ -0,0 +1,22 @@ +from magnumopus.repositories.pantry import Pantry +from magnumopus.models.substance import Substance + +def test_can_add_to_pantry(): + pantry = Pantry() + + substance = Substance() + + pantry.add_substance(substance) + + assert pantry.count_all_substances() == 1 + +def test_can_retrieve_substance_from_pantry_by_nature(): + pantry = Pantry() + + substance = Substance(nature='Mercury') + + pantry.add_substance(substance) + + mercury = pantry.find_substances_by_nature('Mercury')[0] + + assert mercury.nature == 'Mercury' diff --git a/021-conical-continued/magnum_opus/tests/test_substance.py b/021-conical-continued/magnum_opus/tests/test_substance.py new file mode 100644 index 0000000..d00a6f7 --- /dev/null +++ b/021-conical-continued/magnum_opus/tests/test_substance.py @@ -0,0 +1,49 @@ +from magnumopus.models.substance import Substance + +def test_can_cook_substance(): + substance = Substance() + + result = substance.cook() + + assert substance.state == ['cooked'] + +def test_can_wash_substance(): + substance = Substance() + + result = substance.wash() + + assert result.state == ['washed'] + +def test_can_pickle_substance(): + substance = Substance() + + result = substance.pickle() + + assert result.state == ['pickled'] + +def test_can_ferment_substance(): + substance = Substance() + + result = substance.ferment() + + assert substance.state == ['fermented'] + +def test_can_cook_and_ferment_substance(): + substance = Substance() + + result = substance.cook() + result = result.ferment() + + assert substance.state == ['cooked', 'fermented'] + +def test_the_order_of_processes_applied_to_a_substance_matters(): + substance1 = Substance() + result1 = substance1.cook() + result1 = result1.ferment() + + substance2 = Substance() + result2 = substance2.ferment() + result2 = result2.cook() + + assert result1.state != result2.state + assert result1.state == result2.state[::-1] diff --git a/021-conical-continued/magnum_opus/tox.ini b/021-conical-continued/magnum_opus/tox.ini new file mode 100644 index 0000000..d815853 --- /dev/null +++ b/021-conical-continued/magnum_opus/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist = py38 + +[testenv] +deps = pytest +commands = pytest diff --git a/021-conical/Alchemy - A Sequel.ipynb b/021-conical/Alchemy - A Sequel.ipynb new file mode 100644 index 0000000..933372e --- /dev/null +++ b/021-conical/Alchemy - A Sequel.ipynb @@ -0,0 +1,376 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Brewing up a Stone" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Alchemy with Flask and SQLAlchemy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before chemistry, there was alchemy, and the learned elite used to search for the secret of the true cure for all afflictions, the Philosopher's Stone. Using modern technology, we are able to implement it as a web service." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While a plethora of abstruse, esoteric jingo concealed the complex, ever-changing rite, the basic recipe boils down to:\n", + "\n", + "* Cooking - charring\n", + "* Washing - brightening\n", + "* Pickling - yellowing\n", + "* Fermentation - reddening" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This recipe also works for gherkins." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### SQLAlchemy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For those who haven't come across it, SQLAlchemy is a database toolkit and ORM - Object Relational Mapper. That is (amongst other things), it facilitates turning a set of living objects to and from frozen database records. Very alchemical." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "During its construction, its creator used [Martin Fowler's work](https://martinfowler.com/eaaCatalog/) in enterprise architecture (who we talked about before) to incorporate a number of patterns. A few to highlight:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* [Association Table Mapping](https://martinfowler.com/eaaCatalog/associationTableMapping.html)\n", + "* [Inheritance Mapping](https://martinfowler.com/eaaCatalog/inheritanceMappers.html)\n", + "* [Unit of Work](https://martinfowler.com/eaaCatalog/unitOfWork.html)\n", + "* [Embedded Value](https://martinfowler.com/eaaCatalog/embeddedValue.html)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Implementing Alchemy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* One unit of each of the substances Mercury, Salt and Sulphur are mixed, using my \"Alembic\" (mixing pot), giving one unit of another substance, Gloop\n", + "* Any attempt to mix anything other than those three substances, gives Sludge, another substance\n", + "* Substances can undergo several Processes in my Alembic - they can be Cooked, Washed, Pickled or Fermented\n", + "* If Gloop is Cooked, Washed, Pickled and Fermented, in that order, it is the Philosopher's Stone (panacea and cure of all ills)\n", + "\n", + "Final rule:\n", + "\n", + "GROUP 1: When I process a substance, using any process, it becomes a different substance\n", + "\n", + "GROUP 2: When I process a substance, its state changes but is essentially the same substance (NB: mixing is not a process)\n", + "\n", + "* Extension Rule: To process a Substance, at least one unit must be in my Pantry, including Gloop - even when freshly processed/created, it must be stored there before re-use (to cool)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hidePrompt": true + }, + "source": [ + "Each group has 10 minutes to discuss how they plan to approach it - no code, just words and pictures (if you want to screenshare).\n", + "Write down all your names in alphabetical order in Etherpad, and pick a rule for ech person to begin implementing (if you don't have a rule, focus on any models or shared classes)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "At this point, you begin coding, but zero talking or code comments (this time!). Only active code. Use Etherpad to share your code. Every 5 minutes, the next person in the alphabetical list swaps between groups. We'll take a break and, if necessary, do another round." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Test with tox !" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tips" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Try and avoid \"create\", \"update\", \"delete\" or obvious equivalents as verbs - think about the word in the domain." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 12 Factor App" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From https://12factor.net/\n", + "([license](https://github.com/heroku/12factor/blob/master/LICENSE))\n", + "\n", + "1. **Codebase**: One codebase tracked in revision control, many deploys\n", + "2. **Dependencies**: Explicitly declare and isolate dependencies\n", + "3. **Config**: Store config in the environment\n", + "4. **Backing services**: Treat backing services as attached resources\n", + "5. **Build, release, run**: Strictly separate build and run stages\n", + "6. **Processes**: Execute the app as one or more stateless processes\n", + "7. **Port binding**: Export services via port binding\n", + "8. **Concurrency**: Scale out via the process model\n", + "9. **Disposability**: Maximize robustness with fast startup and graceful shutdown\n", + "10. **Dev/prod parity**: Keep development, staging, and production as similar as possible\n", + "11. **Logs**: Treat logs as event streams\n", + "12. **Admin processes**: Run admin/management tasks as one-off processes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the name order in the Etherpad, take your corresponding \"factor\" and add a section to Etherpad to explain why Flask+Docker+SQLAlchemy (or any one of them) can help to achieving it. Focus on why this is different from a big monolithic Python/Java/.NET application. Does the testing approach used by tox help any of these?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extension Exercise" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Looking at https://github.com/docker-library/docs/blob/master/postgres/README.md#-via-docker-stack-deploy-or-docker-compose can you work out how to add a `db:` section to the existing `docker-compose.yml` ?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you did, can you configure `magnumopus` to use that instead?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "How about an nginx proxy, so that you can port-forward to your `web` container from port 8080?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Further reading..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Patterns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "http://io.made.com/blog/2017-09-07-introducing-command-handler.html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://www.infoworld.com/article/3117713/design-patterns-that-i-often-avoid-repository-pattern.html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://github.com/faif/python-patterns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://medium.com/@ssola/building-microservices-with-python-part-i-5240a8dcc2fb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Persistence" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://softwareengineering.stackexchange.com/questions/374047/sqlalchemy-and-ddd-its-own-pattern" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://www.sqlalchemy.org/features.html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "http://dev.nando.audio/2014/04/01/large_apps_with_sqlalchemy__architecture.html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://proofit404.github.io/mappers/usage/" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://stackoverflow.com/questions/2276523/how-do-i-effectively-use-sqlalchemy-with-multiple-ddd-repositories" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Web" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://bobwaycott.com/blog/how-i-use-flask/flask-app-organization/#a-sample-app-layout" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://flask.palletsprojects.com/en/1.1.x/patterns/" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://pypi.org/project/Flask-Injector/" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://github.com/pytest-dev/pytest-flask" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "PythonCourse", + "language": "python", + "name": "pythoncourse" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/021-conical/magnum_opus/.gitignore b/021-conical/magnum_opus/.gitignore new file mode 100644 index 0000000..9fb668e --- /dev/null +++ b/021-conical/magnum_opus/.gitignore @@ -0,0 +1,3 @@ +*.egg-info +.tox +Pipfile diff --git a/021-conical/magnum_opus/MANIFEST.in b/021-conical/magnum_opus/MANIFEST.in new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/021-conical/magnum_opus/MANIFEST.in @@ -0,0 +1 @@ + diff --git a/021-conical/magnum_opus/README.md b/021-conical/magnum_opus/README.md new file mode 100644 index 0000000..b87be82 --- /dev/null +++ b/021-conical/magnum_opus/README.md @@ -0,0 +1,5 @@ +Magnum Opus +=========== + +This recipe maker +and averaged over repeated attempts, returning an average round trip time. diff --git a/021-conical/magnum_opus/RULES.md b/021-conical/magnum_opus/RULES.md new file mode 100644 index 0000000..4438311 --- /dev/null +++ b/021-conical/magnum_opus/RULES.md @@ -0,0 +1,9 @@ +* One unit of each of the substances Mercury, Salt and Sulphur are mixed, using my "Alembic" (mixing pot), giving one unit of another substance, Gloop +* Any attempt to mix anything other than those three substances, gives Sludge, another substance +* Substances can undergo several Processes in my Alembic - they can be Cooked, Washed, Pickled or Fermented +* If Gloop is Cooked, Washed, Pickled and Fermented, in that order, it is the Philosopher's Stone (panacea and cure of all ills) +[* To process a Substance, at least one unit must be in my Pantry, including Gloop - even when freshly processed/created, it must be stored there before re-use (to cool)] + +Final rule: +GROUP 1: When I process a substance, using any process, it becomes a different substance +GROUP 2: When I process a substance, its state changes but is essentially the same substance (NB: mixing is not a process) diff --git a/021-conical/magnum_opus/magnumopus/__init__.py b/021-conical/magnum_opus/magnumopus/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/021-conical/magnum_opus/magnumopus/alembic.py b/021-conical/magnum_opus/magnumopus/alembic.py new file mode 100644 index 0000000..39f02a4 --- /dev/null +++ b/021-conical/magnum_opus/magnumopus/alembic.py @@ -0,0 +1,51 @@ +from .substance import Substance + +class NotEnoughSubstancesToMixException(Exception): + pass + +class UnknownProcessException(Exception): + pass + + +MIXTURES = { + ('Mercury', 'Salt', 'Sulphur'): 'Gloop' +} + + +class Alembic: + _nature_of_unknown_mixture = 'Sludge' + + @staticmethod + def _produce(nature): + return Substance(nature=nature) + + def mix(self, *substances): + if len(substances) < 2: + raise NotEnoughSubstancesToMixException() + + constituents = [substance.nature for substance in substances] + + # This gives us a canonical, ordered way of expressing our + # constituents that we can use as a recipe look-up + ingredient_list = tuple(sorted(constituents)) + + try: + nature = MIXTURES[ingredient_list] + except KeyError: + nature = self._nature_of_unknown_mixture + + return self._produce(nature) + + def process(self, process_name, substance): + if process_name == 'ferment': + result = substance.ferment() + elif process_name == 'cook': + result = substance.cook() + elif process_name == 'wash': + result = substance.wash() + elif process_name == 'pickle': + result = substance.pickle() + else: + raise UnknownProcessException() + + return result diff --git a/021-conical/magnum_opus/magnumopus/pantry.py b/021-conical/magnum_opus/magnumopus/pantry.py new file mode 100644 index 0000000..9e7a1d6 --- /dev/null +++ b/021-conical/magnum_opus/magnumopus/pantry.py @@ -0,0 +1,12 @@ +class Pantry: + def __init__(self): + self._cupboard = [] + + def add_substance(self, substance): + self._cupboard.append(substance) + + def find_substance_by_nature(self, nature): + return [substance for substance in self._cupboard if substance.nature == nature][0] + + def count_all_substances(self): + return len(self._cupboard) diff --git a/021-conical/magnum_opus/magnumopus/substance.py b/021-conical/magnum_opus/magnumopus/substance.py new file mode 100644 index 0000000..828b4c5 --- /dev/null +++ b/021-conical/magnum_opus/magnumopus/substance.py @@ -0,0 +1,23 @@ +class SubstanceMustBeFreshToProcessException(Exception): + pass + +class Substance: + def __init__(self, nature='Unknown'): + self.nature = nature + self.state = [] + + def _process(self, process_name): + self.state.append(process_name) + return self + + def cook(self): + return self._process('cooked') + + def pickle(self): + return self._process('pickled') + + def ferment(self): + return self._process('fermented') + + def wash(self): + return self._process('washed') diff --git a/021-conical/magnum_opus/requirements.txt b/021-conical/magnum_opus/requirements.txt new file mode 100644 index 0000000..99f65af --- /dev/null +++ b/021-conical/magnum_opus/requirements.txt @@ -0,0 +1,5 @@ +numpy +pylint +pyyaml +Click +appdirs \ No newline at end of file diff --git a/021-conical/magnum_opus/setup.cfg b/021-conical/magnum_opus/setup.cfg new file mode 100644 index 0000000..144266f --- /dev/null +++ b/021-conical/magnum_opus/setup.cfg @@ -0,0 +1,19 @@ +[metadata] +name = magnumopus +version = 0.0.1 +author = Phil Weir +author_email = phil.weir@flaxandteal.co.uk +license = GPL +description = Service for cooking up a philosopher's stone +long-description = file:README.md + +[options] +include_package_data = True +packages = find: +python_requires = >=3.6 +install_requires = + appdirs + +[options.packages.find] +exclude = + tests diff --git a/021-conical/magnum_opus/setup.py b/021-conical/magnum_opus/setup.py new file mode 100644 index 0000000..1767837 --- /dev/null +++ b/021-conical/magnum_opus/setup.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +""" +Magnum Opus + +This tool performs alchemical reactions to create +the Philosopher's Stone. + +@author: Phil Weir +""" + +from setuptools import setup + +if __name__ == '__main__': + setup() diff --git a/021-conical/magnum_opus/tests/test_alembic.py b/021-conical/magnum_opus/tests/test_alembic.py new file mode 100644 index 0000000..01fd341 --- /dev/null +++ b/021-conical/magnum_opus/tests/test_alembic.py @@ -0,0 +1,81 @@ +import pytest + +from magnumopus.alembic import Alembic, NotEnoughSubstancesToMixException, UnknownProcessException +from magnumopus.substance import Substance + +def test_can_set_up_my_alembic(): + Alembic() + +def test_can_mix_multiple_substances_in_my_alembic(): + alembic = Alembic() + substance = [Substance() for _ in range(3)] + alembic.mix(*substance) + + substance = [Substance() for _ in range(6)] + alembic.mix(*substance) + +def test_cannot_mix_one_substance_in_my_alembic(): + alembic = Alembic() + substance = Substance() + + with pytest.raises(NotEnoughSubstancesToMixException): + alembic.mix(substance) + +def test_mixing_sulphur_salt_and_mercury_gives_gloop(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + + result = alembic.mix(sulphur, salt, mercury) + + assert result.nature == 'Gloop' + + result = alembic.mix(mercury, sulphur, salt) + + assert result.nature == 'Gloop' + +def test_mixing_other_recipes_gives_sludge(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + gloop = Substance(nature='Gloop') + + result = alembic.mix(sulphur, salt, mercury, sulphur) + + assert result.nature == 'Sludge' + + result = alembic.mix(salt, mercury) + + assert result.nature == 'Sludge' + + result = alembic.mix(gloop, salt, mercury) + + assert result.nature == 'Sludge' + +def test_can_process_substance(): + alembic = Alembic() + + substance = Substance() + result = alembic.process('cook', substance) + + substance = Substance() + cooked_substance = substance.cook() + + assert result.state == cooked_substance.state + + result = alembic.process('ferment', substance) + cooked_fermented_substance = cooked_substance.ferment() + + assert result.state == cooked_fermented_substance.state + +def test_cannot_perform_unknown_process(): + alembic = Alembic() + + substance = Substance() + + with pytest.raises(UnknownProcessException): + alembic.process('boil', substance) diff --git a/021-conical/magnum_opus/tests/test_pantry.py b/021-conical/magnum_opus/tests/test_pantry.py new file mode 100644 index 0000000..84dbd7e --- /dev/null +++ b/021-conical/magnum_opus/tests/test_pantry.py @@ -0,0 +1,22 @@ +from magnumopus.pantry import Pantry +from magnumopus.substance import Substance + +def test_can_add_to_pantry(): + pantry = Pantry() + + substance = Substance() + + pantry.add_substance(substance) + + assert pantry.count_all_substances() == 1 + +def test_can_retrieve_substance_from_pantry_by_nature(): + pantry = Pantry() + + substance = Substance(nature='Mercury') + + pantry.add_substance(substance) + + mercury = pantry.find_substance_by_nature('Mercury') + + assert mercury.nature == 'Mercury' diff --git a/021-conical/magnum_opus/tests/test_substance.py b/021-conical/magnum_opus/tests/test_substance.py new file mode 100644 index 0000000..342cf50 --- /dev/null +++ b/021-conical/magnum_opus/tests/test_substance.py @@ -0,0 +1,49 @@ +from magnumopus.substance import Substance + +def test_can_cook_substance(): + substance = Substance() + + result = substance.cook() + + assert substance.state == ['cooked'] + +def test_can_wash_substance(): + substance = Substance() + + result = substance.wash() + + assert result.state == ['washed'] + +def test_can_pickle_substance(): + substance = Substance() + + result = substance.pickle() + + assert result.state == ['pickled'] + +def test_can_ferment_substance(): + substance = Substance() + + result = substance.ferment() + + assert substance.state == ['fermented'] + +def test_can_cook_and_ferment_substance(): + substance = Substance() + + result = substance.cook() + result = result.ferment() + + assert substance.state == ['cooked', 'fermented'] + +def test_the_order_of_processes_applied_to_a_substance_matters(): + substance1 = Substance() + result1 = substance1.cook() + result1 = result1.ferment() + + substance2 = Substance() + result2 = substance2.ferment() + result2 = result2.cook() + + assert result1.state != result2.state + assert result1.state == result2.state[::-1] diff --git a/021-conical/magnum_opus/tox.ini b/021-conical/magnum_opus/tox.ini new file mode 100644 index 0000000..d815853 --- /dev/null +++ b/021-conical/magnum_opus/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist = py38 + +[testenv] +deps = pytest +commands = pytest diff --git a/022-burette/magnum_opus/.coverage b/022-burette/magnum_opus/.coverage new file mode 100644 index 0000000..acffb03 Binary files /dev/null and b/022-burette/magnum_opus/.coverage differ diff --git a/022-burette/magnum_opus/.gitignore b/022-burette/magnum_opus/.gitignore new file mode 100644 index 0000000..8a3f0fc --- /dev/null +++ b/022-burette/magnum_opus/.gitignore @@ -0,0 +1,4 @@ +*.egg-info +.tox +Pipfile +.env diff --git a/022-burette/magnum_opus/Dockerfile b/022-burette/magnum_opus/Dockerfile new file mode 100644 index 0000000..03a8d6e --- /dev/null +++ b/022-burette/magnum_opus/Dockerfile @@ -0,0 +1,24 @@ +FROM python:3-alpine + +RUN addgroup -S user && adduser user -S -G user + +WORKDIR /home/user/ + +COPY requirements.txt . +COPY gunicorn_config.py . +COPY setup.py . +COPY setup.cfg . +COPY init_entrypoint.sh / + +RUN pip install gunicorn +RUN pip install -r requirements.txt + +USER user + +EXPOSE 5000 + +ENTRYPOINT [] + +CMD gunicorn --config ./gunicorn_config.py magnumopus.index:app + +COPY magnumopus magnumopus diff --git a/022-burette/magnum_opus/MANIFEST.in b/022-burette/magnum_opus/MANIFEST.in new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/022-burette/magnum_opus/MANIFEST.in @@ -0,0 +1 @@ + diff --git a/022-burette/magnum_opus/README.md b/022-burette/magnum_opus/README.md new file mode 100644 index 0000000..94ce180 --- /dev/null +++ b/022-burette/magnum_opus/README.md @@ -0,0 +1,46 @@ +Magnum Opus +=========== + +Recipe maker for the philosopher's stone. + + + python3 -m pytest --cov magnumopus >> README.md + + ============================= test session starts ============================== + platform linux -- Python 3.8.2, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 + rootdir: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus + plugins: pep8-1.0.6, cov-2.10.0 + collected 15 items + + tests/domain/test_alembic.py ....... [ 46%] + tests/domain/test_pantry.py .. [ 60%] + tests/domain/test_substance.py ...... [100%] + + ----------- coverage: platform linux, python 3.8.2-final-0 ----------- + Name Stmts Miss Cover + ------------------------------------------------------------------------ + magnumopus/__init__.py 10 8 20% + magnumopus/config.py 4 4 0% + magnumopus/index.py 2 2 0% + magnumopus/initialize.py 6 6 0% + magnumopus/logger.py 4 4 0% + magnumopus/models/__init__.py 3 1 67% + magnumopus/models/base.py 2 0 100% + magnumopus/models/substance.py 24 0 100% + magnumopus/repositories/__init__.py 0 0 100% + magnumopus/repositories/pantry.py 12 1 92% + magnumopus/repositories/sqlalchemy_pantry.py 15 15 0% + magnumopus/resources/__init__.py 7 7 0% + magnumopus/resources/alembic_instruction.py 26 26 0% + magnumopus/resources/substance.py 28 28 0% + magnumopus/schemas/__init__.py 4 4 0% + magnumopus/schemas/substance_schema.py 11 11 0% + magnumopus/services/__init__.py 0 0 100% + magnumopus/services/alembic.py 32 2 94% + magnumopus/services/alembic_instruction_handler.py 20 20 0% + magnumopus/services/assessor.py 2 2 0% + ------------------------------------------------------------------------ + TOTAL 212 141 33% + + + ============================== 15 passed in 0.38s ============================== diff --git a/022-burette/magnum_opus/RULES.md b/022-burette/magnum_opus/RULES.md new file mode 100644 index 0000000..4438311 --- /dev/null +++ b/022-burette/magnum_opus/RULES.md @@ -0,0 +1,9 @@ +* One unit of each of the substances Mercury, Salt and Sulphur are mixed, using my "Alembic" (mixing pot), giving one unit of another substance, Gloop +* Any attempt to mix anything other than those three substances, gives Sludge, another substance +* Substances can undergo several Processes in my Alembic - they can be Cooked, Washed, Pickled or Fermented +* If Gloop is Cooked, Washed, Pickled and Fermented, in that order, it is the Philosopher's Stone (panacea and cure of all ills) +[* To process a Substance, at least one unit must be in my Pantry, including Gloop - even when freshly processed/created, it must be stored there before re-use (to cool)] + +Final rule: +GROUP 1: When I process a substance, using any process, it becomes a different substance +GROUP 2: When I process a substance, its state changes but is essentially the same substance (NB: mixing is not a process) diff --git a/022-burette/magnum_opus/docker-compose.yml b/022-burette/magnum_opus/docker-compose.yml new file mode 100644 index 0000000..9e5f302 --- /dev/null +++ b/022-burette/magnum_opus/docker-compose.yml @@ -0,0 +1,11 @@ +version: "3" +services: + web: + build: . + environment: + DATABASE_URI: 'sqlite:////docker/storage/storage.db' + volumes: + - ./docker:/docker + - ./magnumopus:/home/user/magnumopus + ports: + - 5000:5000 diff --git a/022-burette/magnum_opus/docker/storage/storage.db b/022-burette/magnum_opus/docker/storage/storage.db new file mode 100644 index 0000000..41e4173 Binary files /dev/null and b/022-burette/magnum_opus/docker/storage/storage.db differ diff --git a/022-burette/magnum_opus/gunicorn_config.py b/022-burette/magnum_opus/gunicorn_config.py new file mode 100644 index 0000000..29db9d9 --- /dev/null +++ b/022-burette/magnum_opus/gunicorn_config.py @@ -0,0 +1,5 @@ +port = '5000' +bind = "0.0.0.0:%s" % port +workers = 1 +timeout = 600 +reload = False diff --git a/022-burette/magnum_opus/init_containers.sh b/022-burette/magnum_opus/init_containers.sh new file mode 100755 index 0000000..0a64c94 --- /dev/null +++ b/022-burette/magnum_opus/init_containers.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +mkdir -p docker/storage + +docker-compose run --user root web /init_entrypoint.sh +docker-compose run web python3 -m magnumopus.initialize diff --git a/022-burette/magnum_opus/init_entrypoint.sh b/022-burette/magnum_opus/init_entrypoint.sh new file mode 100755 index 0000000..8366386 --- /dev/null +++ b/022-burette/magnum_opus/init_entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +chown -R user:user /docker/storage diff --git a/022-burette/magnum_opus/magnumopus/__init__.py b/022-burette/magnum_opus/magnumopus/__init__.py new file mode 100644 index 0000000..e410774 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/__init__.py @@ -0,0 +1,22 @@ +from flask import Flask + +def create_app(): + from . import models, resources, schemas, logger, repositories, injection + + app = Flask(__name__) + + # This could be used to separate by environment + app.config.from_object('magnumopus.config.Config') + + # This helps avoid cyclic dependencies + modules = [] + + modules += logger.init_app(app) + modules += models.init_app(app) + modules += resources.init_app(app) + modules += repositories.init_app(app) + modules += schemas.init_app(app) + + injection.init_app(app, modules) + + return app diff --git a/022-burette/magnum_opus/magnumopus/config.py b/022-burette/magnum_opus/magnumopus/config.py new file mode 100644 index 0000000..637a5ef --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/config.py @@ -0,0 +1,7 @@ +import os + +class Config: + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI', 'sqlite:///:memory:') + SQLALCHEMY_TRACK_MODIFICATIONS = False + + PANTRY_STORE = os.environ.get('MAGNUMOPUS_PANTRY_STORE', 'sqlalchemy') diff --git a/022-burette/magnum_opus/magnumopus/index.py b/022-burette/magnum_opus/magnumopus/index.py new file mode 100644 index 0000000..183c186 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/index.py @@ -0,0 +1,3 @@ +from . import create_app + +app = create_app() diff --git a/022-burette/magnum_opus/magnumopus/initialize.py b/022-burette/magnum_opus/magnumopus/initialize.py new file mode 100644 index 0000000..b251d32 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/initialize.py @@ -0,0 +1,9 @@ +from . import create_app +from .models import db + +if __name__ == "__main__": + # There are nicer ways around this, but this keeps it clear for an example + app = create_app() + + with app.app_context(): + db.create_all() diff --git a/022-burette/magnum_opus/magnumopus/injection.py b/022-burette/magnum_opus/magnumopus/injection.py new file mode 100644 index 0000000..8d74458 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/injection.py @@ -0,0 +1,11 @@ +from flask_injector import FlaskInjector + +def init_app(app, modules): + modules.append(configure_injector) + FlaskInjector(app=app, modules=modules) + +def configure_injector(binder): + """ + Add any general purpose injectables, not included in a submodule + """ + pass diff --git a/022-burette/magnum_opus/magnumopus/logger.py b/022-burette/magnum_opus/magnumopus/logger.py new file mode 100644 index 0000000..b5c4b4f --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/logger.py @@ -0,0 +1,6 @@ +import logging + +def init_app(app): + app.logger.addHandler(logging.StreamHandler()) + app.logger.setLevel(logging.INFO) + return [] diff --git a/022-burette/magnum_opus/magnumopus/models/__init__.py b/022-burette/magnum_opus/magnumopus/models/__init__.py new file mode 100644 index 0000000..63b0a0e --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/models/__init__.py @@ -0,0 +1,11 @@ +from .base import db +from flask_sqlalchemy import SQLAlchemy + +def init_app(app): + db.init_app(app) + return [configure_injector] + +def configure_injector(binding): + binding.bind( + SQLAlchemy, to=db + ) diff --git a/022-burette/magnum_opus/magnumopus/models/base.py b/022-burette/magnum_opus/magnumopus/models/base.py new file mode 100644 index 0000000..f0b13d6 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/models/base.py @@ -0,0 +1,3 @@ +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() diff --git a/022-burette/magnum_opus/magnumopus/models/substance.py b/022-burette/magnum_opus/magnumopus/models/substance.py new file mode 100644 index 0000000..ba91c35 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/models/substance.py @@ -0,0 +1,40 @@ +from . import db +from sqlalchemy_utils import ScalarListType + +class SubstanceMustBeFreshToProcessException(Exception): + pass + +class Substance(db.Model): + __tablename__ = 'substances' + + id = db.Column(db.Integer, primary_key=True) + nature = db.Column(db.String(32), default='Unknown') + state = db.Column(ScalarListType()) + + def __init__(self, nature='Unknown'): + self.state = [] + self.nature = nature + + super(Substance, self).__init__() + + def _process(self, process_name): + # Example of leakage of persistence behaviour into + # domain, due to db.Model -- we must copy the state list to + # ensure it is seen to change... + state = self.state[:] + state.append(process_name) + self.state = state + + return self + + def cook(self): + return self._process('cooked') + + def pickle(self): + return self._process('pickled') + + def ferment(self): + return self._process('fermented') + + def wash(self): + return self._process('washed') diff --git a/022-burette/magnum_opus/magnumopus/repositories/__init__.py b/022-burette/magnum_opus/magnumopus/repositories/__init__.py new file mode 100644 index 0000000..6135fe4 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/repositories/__init__.py @@ -0,0 +1,18 @@ +from .pantry import Pantry +from .list_pantry import ListPantry +from .sqlalchemy_pantry import SQLAlchemyPantry + +PANTRY_STORES = { + 'sqlalchemy': SQLAlchemyPantry, + 'list': ListPantry() # we instantiate this, as we want a singleton cupboard +} + +def init_app(app): + return [lambda binder: configure_injector(binder, app)] + +def configure_injector(binder, app): + pantry_cls = PANTRY_STORES[app.config['PANTRY_STORE']] + + binder.bind( + Pantry, to=pantry_cls + ) diff --git a/022-burette/magnum_opus/magnumopus/repositories/list_pantry.py b/022-burette/magnum_opus/magnumopus/repositories/list_pantry.py new file mode 100644 index 0000000..e14711a --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/repositories/list_pantry.py @@ -0,0 +1,15 @@ +class ListPantry: + def __init__(self): + self._cupboard = [] + + def add_substance(self, substance): + self._cupboard.append(substance) + + def find_substances_by_nature(self, nature): + return [substance for substance in self._cupboard if substance.nature == nature] + + def count_all_substances(self): + return len(self._cupboard) + + def commit(self): + pass diff --git a/022-burette/magnum_opus/magnumopus/repositories/pantry.py b/022-burette/magnum_opus/magnumopus/repositories/pantry.py new file mode 100644 index 0000000..a2cb730 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/repositories/pantry.py @@ -0,0 +1,21 @@ +from abc import ABC, abstractmethod + +class Pantry(ABC): + def __init__(self): + pass + + @abstractmethod + def add_substance(self, substance): + pass + + @abstractmethod + def find_substances_by_nature(self, nature): + pass + + @abstractmethod + def count_all_substances(self): + pass + + @abstractmethod + def commit(self): + pass diff --git a/022-burette/magnum_opus/magnumopus/repositories/sqlalchemy_pantry.py b/022-burette/magnum_opus/magnumopus/repositories/sqlalchemy_pantry.py new file mode 100644 index 0000000..996fe76 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/repositories/sqlalchemy_pantry.py @@ -0,0 +1,28 @@ +from flask_sqlalchemy import SQLAlchemy +from injector import inject + +from ..models.substance import Substance +from ..models import db + +class SQLAlchemyPantry: + @inject + def __init__(self, db: SQLAlchemy): + self._db = db + + # A more involved solution would open and close the pantry... like + # a cupboard door, or a Unit of Work + + # Note how we're committing too frequently? + def add_substance(self, substance): + self._db.session.add(substance) + return substance + + def find_substances_by_nature(self, nature): + substances = Substance.query.filter_by(nature=nature).all() + return substances + + def count_all_substances(self): + return Substance.query.count() + + def commit(self): + self._db.session.commit() diff --git a/022-burette/magnum_opus/magnumopus/resources/__init__.py b/022-burette/magnum_opus/magnumopus/resources/__init__.py new file mode 100644 index 0000000..11345e8 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/resources/__init__.py @@ -0,0 +1,9 @@ +from flask_restful import Api +from . import substance +from . import alembic_instruction + +def init_app(app): + api = Api(app) + substance.init_app(app, api) + alembic_instruction.init_app(app, api) + return [] diff --git a/022-burette/magnum_opus/magnumopus/resources/alembic_instruction.py b/022-burette/magnum_opus/magnumopus/resources/alembic_instruction.py new file mode 100644 index 0000000..2d39fc4 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/resources/alembic_instruction.py @@ -0,0 +1,58 @@ +from flask_restful import Resource, reqparse +from injector import inject +from ..repositories.pantry import Pantry +from ..models.substance import Substance +from ..schemas.substance_schema import SubstanceSchema +from ..services.alembic_instruction_handler import AlembicInstructionHandler, AlembicInstruction + +class AlembicInstructionResource(Resource): + @inject + def __init__(self, pantry: Pantry, substance_schema: SubstanceSchema, parser_fcty=reqparse.RequestParser): + super(AlembicInstructionResource, self).__init__() + + self._pantry = pantry + self._substance_schema = substance_schema + self._parser_fcty = parser_fcty + + def get(self): + """This should return past requests/commands.""" + pass + + def post(self): + """ + Add an instruction for the alembic. + + Note that POST is _not_ assumed to be idempotent, unlike PUT + """ + + parser = self._parser_fcty() + parser.add_argument('instruction_type') + parser.add_argument('action') + parser.add_argument('natures') + + args = parser.parse_args() + instruction_type = args['instruction_type'] + + pantry = self._pantry + + instruction_handler = AlembicInstructionHandler() + + # This could do with deserialization... + instruction = AlembicInstruction( + instruction_type=args.instruction_type, + natures=args.natures.split(','), + action=args.action + ) + + # Crude start at DI... see flask-injector + result = instruction_handler.handle(instruction, pantry) + + pantry.add_substance(result) + + pantry.commit() + + return self._substance_schema.dump(result), 201 + + +def init_app(app, api): + api.add_resource(AlembicInstructionResource, '/alembic_instruction') diff --git a/022-burette/magnum_opus/magnumopus/resources/substance.py b/022-burette/magnum_opus/magnumopus/resources/substance.py new file mode 100644 index 0000000..5e4aafe --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/resources/substance.py @@ -0,0 +1,62 @@ +from flask_restful import Resource, reqparse +from injector import inject +from typing import Dict +from ..repositories.pantry import Pantry +from ..models import db +from ..models.substance import Substance +from ..schemas.substance_schema import SubstanceSchema + +# parser = reqparse.RequestParser() +# parser.add_argument('nature') + +# substance_schema = SubstanceSchema() +# substances_schema = SubstanceSchema(many=True) + +# pantry_cls = SQLAlchemyPantry + + +class SubstanceResource(Resource): + @inject + def __init__(self, pantry: Pantry, substance_schemas: Dict[str, SubstanceSchema], parser_fcty=reqparse.RequestParser): + super(SubstanceResource, self).__init__() + + self._pantry = pantry + self._substance_schema = substance_schemas['one'] + self._substances_schema = substance_schemas['many'] + self._parser_fcty = parser_fcty + + def get(self): + parser = self._parser_fcty() + + parser.add_argument('nature') + + args = parser.parse_args() + + nature = args['nature'] + + substances = self._pantry.find_substances_by_nature(nature) + + return self._substances_schema.dump(substances) + + def post(self): + parser = self._parser_fcty() + + parser.add_argument('nature') + + args = parser.parse_args() + + nature = args['nature'] + + pantry = self._pantry + + substance = Substance(nature=nature) + + pantry.add_substance(substance) + + pantry.commit() + + return self._substance_schema.dump(substance), 201 + + +def init_app(app, api): + api.add_resource(SubstanceResource, '/substance') diff --git a/022-burette/magnum_opus/magnumopus/schemas/__init__.py b/022-burette/magnum_opus/magnumopus/schemas/__init__.py new file mode 100644 index 0000000..7b27dd7 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/schemas/__init__.py @@ -0,0 +1,22 @@ +from typing import Dict +from flask_marshmallow import Marshmallow + +ma = Marshmallow() + +def init_app(app): + ma.init_app(app) + return [configure_injector] + +def configure_injector(binder): + from .substance_schema import SubstanceSchema + + binder.bind( + SubstanceSchema, to=SubstanceSchema() + ) + + binder.multibind( + Dict[str, SubstanceSchema], to={ + 'one': SubstanceSchema(), + 'many': SubstanceSchema(many=True) + } + ) diff --git a/022-burette/magnum_opus/magnumopus/schemas/substance_schema.py b/022-burette/magnum_opus/magnumopus/schemas/substance_schema.py new file mode 100644 index 0000000..2349821 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/schemas/substance_schema.py @@ -0,0 +1,19 @@ +from marshmallow import fields + +from . import ma + +from ..models.substance import Substance +from ..services.assessor import assess_whether_substance_is_philosophers_stone + +class SubstanceSchema(ma.SQLAlchemySchema): + is_philosophers_stone = fields.Function( + assess_whether_substance_is_philosophers_stone + ) + + class Meta: + model = Substance + fields = ('id', 'nature', 'is_philosophers_stone', 'state') + + id = ma.auto_field() + nature = ma.auto_field() + state = fields.Function(lambda model: model.state or []) diff --git a/022-burette/magnum_opus/magnumopus/services/__init__.py b/022-burette/magnum_opus/magnumopus/services/__init__.py new file mode 100644 index 0000000..561fd25 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/services/__init__.py @@ -0,0 +1,9 @@ +from .alembic import Alembic + +def init_app(app): + return [configure_injector] + +def configure_injector(binder): + binder.bind( + Alembic, to=Alembic + ) diff --git a/022-burette/magnum_opus/magnumopus/services/alembic.py b/022-burette/magnum_opus/magnumopus/services/alembic.py new file mode 100644 index 0000000..5fc05b2 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/services/alembic.py @@ -0,0 +1,51 @@ +from ..models.substance import Substance + +class NotEnoughSubstancesToMixException(Exception): + pass + +class UnknownProcessException(Exception): + pass + + +MIXTURES = { + ('Mercury', 'Salt', 'Sulphur'): 'Gloop' +} + + +class Alembic: + _nature_of_unknown_mixture = 'Sludge' + + @staticmethod + def _produce(nature): + return Substance(nature=nature) + + def mix(self, *substances): + if len(substances) < 2: + raise NotEnoughSubstancesToMixException() + + constituents = [substance.nature for substance in substances] + + # This gives us a canonical, ordered way of expressing our + # constituents that we can use as a recipe look-up + ingredient_list = tuple(sorted(constituents)) + + try: + nature = MIXTURES[ingredient_list] + except KeyError: + nature = self._nature_of_unknown_mixture + + return self._produce(nature) + + def process(self, process_name, substance): + if process_name == 'ferment': + result = substance.ferment() + elif process_name == 'cook': + result = substance.cook() + elif process_name == 'wash': + result = substance.wash() + elif process_name == 'pickle': + result = substance.pickle() + else: + raise UnknownProcessException() + + return result diff --git a/022-burette/magnum_opus/magnumopus/services/alembic_instruction_handler.py b/022-burette/magnum_opus/magnumopus/services/alembic_instruction_handler.py new file mode 100644 index 0000000..54fbb40 --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/services/alembic_instruction_handler.py @@ -0,0 +1,36 @@ +from dataclasses import dataclass +from injector import inject + +from .alembic import Alembic +from ..repositories.pantry import Pantry + +class UnknownAlembicInstructionException(Exception): + pass + +@dataclass +class AlembicInstruction: + instruction_type: str + natures: list + action: str = '' + +class AlembicInstructionHandler: + @inject + def handle(self, instruction: AlembicInstruction, pantry: Pantry): + natures = instruction.natures + action = instruction.action + instruction_type = instruction.instruction_type + + # Clearly need some validation here! + substances = [pantry.find_substances_by_nature(nature)[0] for nature in natures] + + alembic = Alembic() + + if instruction_type == 'mix': + result = alembic.mix(*substances) + elif instruction_type == 'process': + result = alembic.process(action, substances[0]) + else: + raise UnknownAlembicInstructionException(f'Unknown instruction: {action}') + + print(result.state, result.id, 'x') + return result diff --git a/022-burette/magnum_opus/magnumopus/services/assessor.py b/022-burette/magnum_opus/magnumopus/services/assessor.py new file mode 100644 index 0000000..94d564d --- /dev/null +++ b/022-burette/magnum_opus/magnumopus/services/assessor.py @@ -0,0 +1,2 @@ +def assess_whether_substance_is_philosophers_stone(substance): + return substance.nature == 'Gloop' and substance.state == ['cooked', 'washed', 'pickled', 'fermented'] diff --git a/022-burette/magnum_opus/requirements.txt b/022-burette/magnum_opus/requirements.txt new file mode 100644 index 0000000..4c1dc81 --- /dev/null +++ b/022-burette/magnum_opus/requirements.txt @@ -0,0 +1,8 @@ +appdirs +flask +flask-restful +flask-marshmallow +flask-sqlalchemy +flask-injector +marshmallow-sqlalchemy +sqlalchemy-utils diff --git a/022-burette/magnum_opus/setup.cfg b/022-burette/magnum_opus/setup.cfg new file mode 100644 index 0000000..bfffc70 --- /dev/null +++ b/022-burette/magnum_opus/setup.cfg @@ -0,0 +1,34 @@ +[metadata] +name = magnumopus +version = 0.0.1 +author = Phil Weir +author_email = phil.weir@flaxandteal.co.uk +license = GPL +description = Service for cooking up a philosopher's stone +long-description = file:README.md + +[options] +include_package_data = True +packages = find: +python_requires = >=3.6 +install_requires = + appdirs + flask-restful + flask-marshmallow + flask-sqlalchemy + flask-injector + sqlalchemy-utils + marshmallow-sqlalchemy + flask + +[options.extras_require] +dev = + pytest + pytest-pep8 + pytest-cov + pytest-flask + pytest-flask-sqlalchemy + +[options.packages.find] +exclude = + tests diff --git a/022-burette/magnum_opus/setup.py b/022-burette/magnum_opus/setup.py new file mode 100644 index 0000000..1767837 --- /dev/null +++ b/022-burette/magnum_opus/setup.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +""" +Magnum Opus + +This tool performs alchemical reactions to create +the Philosopher's Stone. + +@author: Phil Weir +""" + +from setuptools import setup + +if __name__ == '__main__': + setup() diff --git a/022-burette/magnum_opus/tests/__init__.py b/022-burette/magnum_opus/tests/__init__.py new file mode 100644 index 0000000..c09f99d --- /dev/null +++ b/022-burette/magnum_opus/tests/__init__.py @@ -0,0 +1,4 @@ + +def is_dictionary_inside(d1, d2): + return d1.items() <= d2.items() + diff --git a/022-burette/magnum_opus/tests/application/.coverage b/022-burette/magnum_opus/tests/application/.coverage new file mode 100644 index 0000000..0e5750b Binary files /dev/null and b/022-burette/magnum_opus/tests/application/.coverage differ diff --git a/022-burette/magnum_opus/tests/application/__init__.py b/022-burette/magnum_opus/tests/application/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/022-burette/magnum_opus/tests/application/test_alembic_instruction_resource.py b/022-burette/magnum_opus/tests/application/test_alembic_instruction_resource.py new file mode 100644 index 0000000..063bb92 --- /dev/null +++ b/022-burette/magnum_opus/tests/application/test_alembic_instruction_resource.py @@ -0,0 +1,47 @@ +import pytest +from magnumopus import create_app +from .. import is_dictionary_inside +from .test_substance_resource import create_substance_request + +def create_alembic_instruction_request(client, instruction_type, natures, action=None): + data = { + 'instruction_type': instruction_type, + 'natures': ','.join(natures) + } + + if action is not None: + data['action'] = action + + return client.post('/alembic_instruction', data=data) + +def test_create_alembic_mix_instruction(client): + create_substance_request(client, ['Mercury']) + create_substance_request(client, ['Salt']) + create_substance_request(client, ['Sulphur']) + + rv = create_alembic_instruction_request(client, 'mix', ['Mercury', 'Salt', 'Sulphur']) + + assert rv.status_code == 201 + + content = rv.get_json() + + assert is_dictionary_inside({ + 'nature': 'Gloop', + 'state': [], + 'is_philosophers_stone': False + }, content) + +def test_create_alembic_process_instruction(client): + create_substance_request(client, ['Mercury']) + + rv = create_alembic_instruction_request(client, 'process', ['Mercury'], 'cook') + + assert rv.status_code == 201 + + content = rv.get_json() + + assert is_dictionary_inside({ + 'nature': 'Mercury', + 'state': ['cooked'], + 'is_philosophers_stone': False + }, content) diff --git a/022-burette/magnum_opus/tests/application/test_philosophers_stone.py b/022-burette/magnum_opus/tests/application/test_philosophers_stone.py new file mode 100644 index 0000000..ca25fb7 --- /dev/null +++ b/022-burette/magnum_opus/tests/application/test_philosophers_stone.py @@ -0,0 +1,7 @@ +import pytest +from magnumopus import create_app +from .. import is_dictionary_inside + + +def test_create_philosophers_stone(client): + pass diff --git a/022-burette/magnum_opus/tests/application/test_substance_resource.py b/022-burette/magnum_opus/tests/application/test_substance_resource.py new file mode 100644 index 0000000..ed85af9 --- /dev/null +++ b/022-burette/magnum_opus/tests/application/test_substance_resource.py @@ -0,0 +1,50 @@ +import pytest +from magnumopus import create_app +from .. import is_dictionary_inside + +def create_substance_request(client, nature): + return client.post('/substance', data={ + 'nature': nature + }) + +def index_substances_request(client, nature): + return client.get(f'/substance?nature={nature}') + +def test_create_substance(client): + rv = create_substance_request(client, 'Sulphur') + + assert rv.status_code == 201 + + content = rv.get_json() + + assert type(content['id']) is int + + assert is_dictionary_inside({ + 'nature': 'Sulphur', + 'state': [], + 'is_philosophers_stone': False + }, content) + + +def test_get_substances(client): + create_substance_request(client, 'Sulphur') + + rv = index_substances_request(client, 'Sulphur') + + assert rv.status_code == 200 + + content = rv.get_json() + + assert type(content) is list + + assert len(content) == 1 + + assert type(content[0]['id']) is int + + assert is_dictionary_inside({ + 'nature': 'Sulphur', + 'state': [], + 'is_philosophers_stone': False + }, content[0]) + +# We also need non-happy paths! diff --git a/022-burette/magnum_opus/tests/conftest.py b/022-burette/magnum_opus/tests/conftest.py new file mode 100644 index 0000000..19d7e10 --- /dev/null +++ b/022-burette/magnum_opus/tests/conftest.py @@ -0,0 +1,23 @@ +import pytest +from magnumopus import create_app +from magnumopus.models import db + +@pytest.fixture(scope='session') +def app(): + app = create_app() + return app + + +@pytest.fixture(scope='session') +def _db(app): + with app.app_context(): + db.create_all() + return db + +@pytest.fixture +def client(app): + with app.test_client() as client: + with app.app_context(): + db.create_all() + yield client + db.drop_all() diff --git a/022-burette/magnum_opus/tests/domain/__init__.py b/022-burette/magnum_opus/tests/domain/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/022-burette/magnum_opus/tests/domain/test_alembic.py b/022-burette/magnum_opus/tests/domain/test_alembic.py new file mode 100644 index 0000000..cd67657 --- /dev/null +++ b/022-burette/magnum_opus/tests/domain/test_alembic.py @@ -0,0 +1,81 @@ +import pytest + +from magnumopus.services.alembic import Alembic, NotEnoughSubstancesToMixException, UnknownProcessException +from magnumopus.models.substance import Substance + +def test_can_set_up_my_alembic(): + Alembic() + +def test_can_mix_multiple_substances_in_my_alembic(): + alembic = Alembic() + substance = [Substance() for _ in range(3)] + alembic.mix(*substance) + + substance = [Substance() for _ in range(6)] + alembic.mix(*substance) + +def test_cannot_mix_one_substance_in_my_alembic(): + alembic = Alembic() + substance = Substance() + + with pytest.raises(NotEnoughSubstancesToMixException): + alembic.mix(substance) + +def test_mixing_sulphur_salt_and_mercury_gives_gloop(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + + result = alembic.mix(sulphur, salt, mercury) + + assert result.nature == 'Gloop' + + result = alembic.mix(mercury, sulphur, salt) + + assert result.nature == 'Gloop' + +def test_mixing_other_recipes_gives_sludge(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + gloop = Substance(nature='Gloop') + + result = alembic.mix(sulphur, salt, mercury, sulphur) + + assert result.nature == 'Sludge' + + result = alembic.mix(salt, mercury) + + assert result.nature == 'Sludge' + + result = alembic.mix(gloop, salt, mercury) + + assert result.nature == 'Sludge' + +def test_can_process_substance(): + alembic = Alembic() + + substance = Substance() + result = alembic.process('cook', substance) + + substance = Substance() + cooked_substance = substance.cook() + + assert result.state == cooked_substance.state + + result = alembic.process('ferment', substance) + cooked_fermented_substance = cooked_substance.ferment() + + assert result.state == cooked_fermented_substance.state + +def test_cannot_perform_unknown_process(): + alembic = Alembic() + + substance = Substance() + + with pytest.raises(UnknownProcessException): + alembic.process('boil', substance) diff --git a/022-burette/magnum_opus/tests/domain/test_alembic_instruction_handler.py b/022-burette/magnum_opus/tests/domain/test_alembic_instruction_handler.py new file mode 100644 index 0000000..ccb2f96 --- /dev/null +++ b/022-burette/magnum_opus/tests/domain/test_alembic_instruction_handler.py @@ -0,0 +1,37 @@ +import pytest + +from magnumopus.services.alembic_instruction_handler import AlembicInstruction, AlembicInstructionHandler +from magnumopus.repositories.list_pantry import ListPantry +from magnumopus.models.substance import Substance + +@pytest.fixture +def instruction_unknown(): + return AlembicInstruction( + 'saute', + ['Sulphur'], + 'cook' + ) + +@pytest.fixture +def instruction(): + return AlembicInstruction( + 'process', + ['Sludge'], + 'cook' + ) + +@pytest.fixture +def pantry(): + pantry = ListPantry() + + substance = Substance(nature='Sludge') + pantry.add_substance(substance) + + substance = Substance(nature='Sulphur') + pantry.add_substance(substance) + + return pantry + +def test_can_set_up_my_alembic_instruction_handler(instruction, pantry): + handler = AlembicInstructionHandler() + handler.handle(instruction, pantry) diff --git a/022-burette/magnum_opus/tests/domain/test_pantry.py b/022-burette/magnum_opus/tests/domain/test_pantry.py new file mode 100644 index 0000000..464ed15 --- /dev/null +++ b/022-burette/magnum_opus/tests/domain/test_pantry.py @@ -0,0 +1,43 @@ +import pytest + +from magnumopus.repositories.list_pantry import ListPantry +from magnumopus.repositories.sqlalchemy_pantry import SQLAlchemyPantry +from magnumopus.models.substance import Substance + +@pytest.fixture +def list_pantry(): + return ListPantry() + +@pytest.fixture +def sqlalchemy_pantry(_db): + return SQLAlchemyPantry(_db) + +@pytest.fixture +def pantries(list_pantry, sqlalchemy_pantry): + return { + 'list': list_pantry, + 'sqlalchemy': sqlalchemy_pantry + } + +# We may want other pantry-specific tests, but bear in mind LSP +@pytest.mark.parametrize('pantry_type', ['list', 'sqlalchemy']) +def test_can_add_to_pantry(pantry_type, pantries): + pantry = pantries[pantry_type] + + substance = Substance() + + pantry.add_substance(substance) + + assert pantry.count_all_substances() == 1 + +@pytest.mark.parametrize('pantry_type', ['list', 'sqlalchemy']) +def test_can_retrieve_substance_from_pantry_by_nature(pantry_type, pantries): + pantry = pantries[pantry_type] + + substance = Substance(nature='Mercury') + + pantry.add_substance(substance) + + mercury = pantry.find_substances_by_nature('Mercury')[0] + + assert mercury.nature == 'Mercury' diff --git a/022-burette/magnum_opus/tests/domain/test_substance.py b/022-burette/magnum_opus/tests/domain/test_substance.py new file mode 100644 index 0000000..d00a6f7 --- /dev/null +++ b/022-burette/magnum_opus/tests/domain/test_substance.py @@ -0,0 +1,49 @@ +from magnumopus.models.substance import Substance + +def test_can_cook_substance(): + substance = Substance() + + result = substance.cook() + + assert substance.state == ['cooked'] + +def test_can_wash_substance(): + substance = Substance() + + result = substance.wash() + + assert result.state == ['washed'] + +def test_can_pickle_substance(): + substance = Substance() + + result = substance.pickle() + + assert result.state == ['pickled'] + +def test_can_ferment_substance(): + substance = Substance() + + result = substance.ferment() + + assert substance.state == ['fermented'] + +def test_can_cook_and_ferment_substance(): + substance = Substance() + + result = substance.cook() + result = result.ferment() + + assert substance.state == ['cooked', 'fermented'] + +def test_the_order_of_processes_applied_to_a_substance_matters(): + substance1 = Substance() + result1 = substance1.cook() + result1 = result1.ferment() + + substance2 = Substance() + result2 = substance2.ferment() + result2 = result2.cook() + + assert result1.state != result2.state + assert result1.state == result2.state[::-1] diff --git a/022-burette/magnum_opus/tox.ini b/022-burette/magnum_opus/tox.ini new file mode 100644 index 0000000..d815853 --- /dev/null +++ b/022-burette/magnum_opus/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist = py38 + +[testenv] +deps = pytest +commands = pytest diff --git a/022-burette/magnum_opus_ii/.coverage b/022-burette/magnum_opus_ii/.coverage new file mode 100644 index 0000000..acffb03 Binary files /dev/null and b/022-burette/magnum_opus_ii/.coverage differ diff --git a/022-burette/magnum_opus_ii/.gitignore b/022-burette/magnum_opus_ii/.gitignore new file mode 100644 index 0000000..8a3f0fc --- /dev/null +++ b/022-burette/magnum_opus_ii/.gitignore @@ -0,0 +1,4 @@ +*.egg-info +.tox +Pipfile +.env diff --git a/022-burette/magnum_opus_ii/Dockerfile b/022-burette/magnum_opus_ii/Dockerfile new file mode 100644 index 0000000..0c7c8cf --- /dev/null +++ b/022-burette/magnum_opus_ii/Dockerfile @@ -0,0 +1,24 @@ +FROM python:3-alpine + +RUN addgroup -S user && adduser user -S -G user + +WORKDIR /home/user/ + +COPY requirements.txt . +COPY gunicorn_config.py . +COPY setup.py . +COPY setup.cfg . +COPY init_entrypoint.sh / + +RUN pip install hypercorn +RUN pip install -r requirements.txt + +USER user + +EXPOSE 5000 + +ENTRYPOINT [] + +CMD hypercorn --config python:./gunicorn_config.py magnumopus.index:app + +COPY magnumopus magnumopus diff --git a/022-burette/magnum_opus_ii/MANIFEST.in b/022-burette/magnum_opus_ii/MANIFEST.in new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/022-burette/magnum_opus_ii/MANIFEST.in @@ -0,0 +1 @@ + diff --git a/022-burette/magnum_opus_ii/README.md b/022-burette/magnum_opus_ii/README.md new file mode 100644 index 0000000..94ce180 --- /dev/null +++ b/022-burette/magnum_opus_ii/README.md @@ -0,0 +1,46 @@ +Magnum Opus +=========== + +Recipe maker for the philosopher's stone. + + + python3 -m pytest --cov magnumopus >> README.md + + ============================= test session starts ============================== + platform linux -- Python 3.8.2, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 + rootdir: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus + plugins: pep8-1.0.6, cov-2.10.0 + collected 15 items + + tests/domain/test_alembic.py ....... [ 46%] + tests/domain/test_pantry.py .. [ 60%] + tests/domain/test_substance.py ...... [100%] + + ----------- coverage: platform linux, python 3.8.2-final-0 ----------- + Name Stmts Miss Cover + ------------------------------------------------------------------------ + magnumopus/__init__.py 10 8 20% + magnumopus/config.py 4 4 0% + magnumopus/index.py 2 2 0% + magnumopus/initialize.py 6 6 0% + magnumopus/logger.py 4 4 0% + magnumopus/models/__init__.py 3 1 67% + magnumopus/models/base.py 2 0 100% + magnumopus/models/substance.py 24 0 100% + magnumopus/repositories/__init__.py 0 0 100% + magnumopus/repositories/pantry.py 12 1 92% + magnumopus/repositories/sqlalchemy_pantry.py 15 15 0% + magnumopus/resources/__init__.py 7 7 0% + magnumopus/resources/alembic_instruction.py 26 26 0% + magnumopus/resources/substance.py 28 28 0% + magnumopus/schemas/__init__.py 4 4 0% + magnumopus/schemas/substance_schema.py 11 11 0% + magnumopus/services/__init__.py 0 0 100% + magnumopus/services/alembic.py 32 2 94% + magnumopus/services/alembic_instruction_handler.py 20 20 0% + magnumopus/services/assessor.py 2 2 0% + ------------------------------------------------------------------------ + TOTAL 212 141 33% + + + ============================== 15 passed in 0.38s ============================== diff --git a/022-burette/magnum_opus_ii/RULES.md b/022-burette/magnum_opus_ii/RULES.md new file mode 100644 index 0000000..4438311 --- /dev/null +++ b/022-burette/magnum_opus_ii/RULES.md @@ -0,0 +1,9 @@ +* One unit of each of the substances Mercury, Salt and Sulphur are mixed, using my "Alembic" (mixing pot), giving one unit of another substance, Gloop +* Any attempt to mix anything other than those three substances, gives Sludge, another substance +* Substances can undergo several Processes in my Alembic - they can be Cooked, Washed, Pickled or Fermented +* If Gloop is Cooked, Washed, Pickled and Fermented, in that order, it is the Philosopher's Stone (panacea and cure of all ills) +[* To process a Substance, at least one unit must be in my Pantry, including Gloop - even when freshly processed/created, it must be stored there before re-use (to cool)] + +Final rule: +GROUP 1: When I process a substance, using any process, it becomes a different substance +GROUP 2: When I process a substance, its state changes but is essentially the same substance (NB: mixing is not a process) diff --git a/022-burette/magnum_opus_ii/docker-compose.yml b/022-burette/magnum_opus_ii/docker-compose.yml new file mode 100644 index 0000000..34d2be6 --- /dev/null +++ b/022-burette/magnum_opus_ii/docker-compose.yml @@ -0,0 +1,11 @@ +version: "3" +services: + web_async: + build: . + environment: + DATABASE_URI: 'sqlite:////docker/storage/storage.db' + volumes: + - ./docker:/docker + - ./magnumopus:/home/user/magnumopus + ports: + - 5000:5000 diff --git a/022-burette/magnum_opus_ii/docker/storage/storage.db b/022-burette/magnum_opus_ii/docker/storage/storage.db new file mode 100644 index 0000000..41e4173 Binary files /dev/null and b/022-burette/magnum_opus_ii/docker/storage/storage.db differ diff --git a/022-burette/magnum_opus_ii/gunicorn_config.py b/022-burette/magnum_opus_ii/gunicorn_config.py new file mode 100644 index 0000000..29db9d9 --- /dev/null +++ b/022-burette/magnum_opus_ii/gunicorn_config.py @@ -0,0 +1,5 @@ +port = '5000' +bind = "0.0.0.0:%s" % port +workers = 1 +timeout = 600 +reload = False diff --git a/022-burette/magnum_opus_ii/init_containers.sh b/022-burette/magnum_opus_ii/init_containers.sh new file mode 100755 index 0000000..0a64c94 --- /dev/null +++ b/022-burette/magnum_opus_ii/init_containers.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +mkdir -p docker/storage + +docker-compose run --user root web /init_entrypoint.sh +docker-compose run web python3 -m magnumopus.initialize diff --git a/022-burette/magnum_opus_ii/init_entrypoint.sh b/022-burette/magnum_opus_ii/init_entrypoint.sh new file mode 100755 index 0000000..8366386 --- /dev/null +++ b/022-burette/magnum_opus_ii/init_entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +chown -R user:user /docker/storage diff --git a/022-burette/magnum_opus_ii/magnumopus/__init__.py b/022-burette/magnum_opus_ii/magnumopus/__init__.py new file mode 100644 index 0000000..3d8522e --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/__init__.py @@ -0,0 +1,22 @@ +from quart_openapi import Pint + +def create_app(): + from . import models, resources, schemas, logger, repositories, injection + + app = Pint(__name__, title='Magnum Opus') + + # This could be used to separate by environment + app.config.from_object('magnumopus.config.Config') + + # This helps avoid cyclic dependencies + modules = [] + + modules += logger.init_app(app) + modules += models.init_app(app) + modules += resources.init_app(app) + modules += repositories.init_app(app) + modules += schemas.init_app(app) + + injection.init_app(app, modules) + + return app diff --git a/022-burette/magnum_opus_ii/magnumopus/config.py b/022-burette/magnum_opus_ii/magnumopus/config.py new file mode 100644 index 0000000..a9899f9 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/config.py @@ -0,0 +1,7 @@ +import os + +class Config: + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI', 'sqlite:///:memory:') + SQLALCHEMY_TRACK_MODIFICATIONS = False + + PANTRY_STORE = os.environ.get('MAGNUMOPUS_PANTRY_STORE', 'list') diff --git a/022-burette/magnum_opus_ii/magnumopus/index.py b/022-burette/magnum_opus_ii/magnumopus/index.py new file mode 100644 index 0000000..183c186 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/index.py @@ -0,0 +1,3 @@ +from . import create_app + +app = create_app() diff --git a/022-burette/magnum_opus_ii/magnumopus/initialize.py b/022-burette/magnum_opus_ii/magnumopus/initialize.py new file mode 100644 index 0000000..b251d32 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/initialize.py @@ -0,0 +1,9 @@ +from . import create_app +from .models import db + +if __name__ == "__main__": + # There are nicer ways around this, but this keeps it clear for an example + app = create_app() + + with app.app_context(): + db.create_all() diff --git a/022-burette/magnum_opus_ii/magnumopus/injection.py b/022-burette/magnum_opus_ii/magnumopus/injection.py new file mode 100644 index 0000000..00a8b45 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/injection.py @@ -0,0 +1,26 @@ +from injector import Injector +from quart.views import MethodViewType + +class ViewInjectorMeta(MethodViewType): + def get_injector(self): + return self.get_app().extensions['injector'] + + def __call__(cls, *args, **kwargs): + return cls.get_injector().create_object( + cls.__bases__[0], + additional_kwargs=kwargs + ) + +def init_app(app, modules): + modules.append(configure_injector) + + injctr = Injector() + for module in modules: + injctr.binder.install(module) + app.extensions['injector'] = injctr + +def configure_injector(binder): + """ + Add any general purpose injectables, not included in a submodule + """ + pass diff --git a/022-burette/magnum_opus_ii/magnumopus/logger.py b/022-burette/magnum_opus_ii/magnumopus/logger.py new file mode 100644 index 0000000..b5c4b4f --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/logger.py @@ -0,0 +1,6 @@ +import logging + +def init_app(app): + app.logger.addHandler(logging.StreamHandler()) + app.logger.setLevel(logging.INFO) + return [] diff --git a/022-burette/magnum_opus_ii/magnumopus/models/__init__.py b/022-burette/magnum_opus_ii/magnumopus/models/__init__.py new file mode 100644 index 0000000..de02858 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/models/__init__.py @@ -0,0 +1,11 @@ +from .base import db +from flask_sqlalchemy import SQLAlchemy + +def init_app(app): + # db.init_app(app) + return [configure_injector] + +def configure_injector(binding): + binding.bind( + SQLAlchemy, to=db + ) diff --git a/022-burette/magnum_opus_ii/magnumopus/models/base.py b/022-burette/magnum_opus_ii/magnumopus/models/base.py new file mode 100644 index 0000000..f0b13d6 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/models/base.py @@ -0,0 +1,3 @@ +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() diff --git a/022-burette/magnum_opus_ii/magnumopus/models/substance.py b/022-burette/magnum_opus_ii/magnumopus/models/substance.py new file mode 100644 index 0000000..ba91c35 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/models/substance.py @@ -0,0 +1,40 @@ +from . import db +from sqlalchemy_utils import ScalarListType + +class SubstanceMustBeFreshToProcessException(Exception): + pass + +class Substance(db.Model): + __tablename__ = 'substances' + + id = db.Column(db.Integer, primary_key=True) + nature = db.Column(db.String(32), default='Unknown') + state = db.Column(ScalarListType()) + + def __init__(self, nature='Unknown'): + self.state = [] + self.nature = nature + + super(Substance, self).__init__() + + def _process(self, process_name): + # Example of leakage of persistence behaviour into + # domain, due to db.Model -- we must copy the state list to + # ensure it is seen to change... + state = self.state[:] + state.append(process_name) + self.state = state + + return self + + def cook(self): + return self._process('cooked') + + def pickle(self): + return self._process('pickled') + + def ferment(self): + return self._process('fermented') + + def wash(self): + return self._process('washed') diff --git a/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py b/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py new file mode 100644 index 0000000..6135fe4 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py @@ -0,0 +1,18 @@ +from .pantry import Pantry +from .list_pantry import ListPantry +from .sqlalchemy_pantry import SQLAlchemyPantry + +PANTRY_STORES = { + 'sqlalchemy': SQLAlchemyPantry, + 'list': ListPantry() # we instantiate this, as we want a singleton cupboard +} + +def init_app(app): + return [lambda binder: configure_injector(binder, app)] + +def configure_injector(binder, app): + pantry_cls = PANTRY_STORES[app.config['PANTRY_STORE']] + + binder.bind( + Pantry, to=pantry_cls + ) diff --git a/022-burette/magnum_opus_ii/magnumopus/repositories/list_pantry.py b/022-burette/magnum_opus_ii/magnumopus/repositories/list_pantry.py new file mode 100644 index 0000000..9d6dbe4 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/repositories/list_pantry.py @@ -0,0 +1,26 @@ +class ListPantry: + def __init__(self): + self._cupboard = [] + + def empty_pantry(self): + self._cupboard = [] + + def add_substance(self, substance): + self._cupboard.append(substance) + + def find_substances_by_nature(self, nature): + return [substance for substance in self._cupboard if substance.nature == nature] + + def count_all_substances(self): + return len(self._cupboard) + + def commit(self): + # Give each substance an ID, if it does not have one + free_ids = iter( + set(range(1, len(self._cupboard) + 1)) - + set([substance.id for substance in self._cupboard if substance]) + ) + + for substance in self._cupboard: + if not substance.id: + substance.id = next(free_ids) diff --git a/022-burette/magnum_opus_ii/magnumopus/repositories/pantry.py b/022-burette/magnum_opus_ii/magnumopus/repositories/pantry.py new file mode 100644 index 0000000..3a342a5 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/repositories/pantry.py @@ -0,0 +1,25 @@ +from abc import ABC, abstractmethod + +class Pantry(ABC): + def __init__(self): + pass + + @abstractmethod + def do_empty(self): + pass + + @abstractmethod + def add_substance(self, substance): + pass + + @abstractmethod + def find_substances_by_nature(self, nature): + pass + + @abstractmethod + def count_all_substances(self): + pass + + @abstractmethod + def commit(self): + pass diff --git a/022-burette/magnum_opus_ii/magnumopus/repositories/sqlalchemy_pantry.py b/022-burette/magnum_opus_ii/magnumopus/repositories/sqlalchemy_pantry.py new file mode 100644 index 0000000..d9135f0 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/repositories/sqlalchemy_pantry.py @@ -0,0 +1,31 @@ +from flask_sqlalchemy import SQLAlchemy +from injector import inject + +from ..models.substance import Substance +from ..models import db + +class SQLAlchemyPantry: + @inject + def __init__(self, db: SQLAlchemy): + self._db = db + + def empty_pantry(self): + Substance.query.delete() + + # A more involved solution would open and close the pantry... like + # a cupboard door, or a Unit of Work + + # Note how we're committing too frequently? + def add_substance(self, substance): + self._db.session.add(substance) + return substance + + def find_substances_by_nature(self, nature): + substances = Substance.query.filter_by(nature=nature).all() + return substances + + def count_all_substances(self): + return Substance.query.count() + + def commit(self): + self._db.session.commit() diff --git a/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py b/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py new file mode 100644 index 0000000..7088c1e --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py @@ -0,0 +1,7 @@ +from . import substance +from . import alembic_instruction + +def init_app(app): + substance.init_app(app) + alembic_instruction.init_app(app) + return [] diff --git a/022-burette/magnum_opus_ii/magnumopus/resources/alembic_instruction.py b/022-burette/magnum_opus_ii/magnumopus/resources/alembic_instruction.py new file mode 100644 index 0000000..a6ff22c --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/resources/alembic_instruction.py @@ -0,0 +1,57 @@ +from quart import request +from quart_openapi import Resource +from injector import inject +from ..injection import ViewInjectorMeta +from ..repositories.pantry import Pantry +from ..models.substance import Substance +from ..schemas.substance_schema import SubstanceSchema +from ..services.alembic_instruction_handler import AlembicInstructionHandler, AlembicInstruction + +class AlembicInstructionResource(Resource): + @inject + def __init__(self, pantry: Pantry, substance_schema: SubstanceSchema): + super(AlembicInstructionResource, self).__init__() + + self._pantry = pantry + self._substance_schema = substance_schema + + async def get(self): + """This should return past requests/commands.""" + pass + + async def post(self): + """ + Add an instruction for the alembic. + + Note that POST is _not_ assumed to be idempotent, unlike PUT + """ + + args = await request.get_json() + + instruction_type = args['instruction_type'] + + pantry = self._pantry + + instruction_handler = AlembicInstructionHandler() + + # This could do with deserialization... + instruction = AlembicInstruction( + instruction_type=args['instruction_type'], + natures=args['natures'].split(','), + action=args['action'] if 'action' in args else '' + ) + + result = instruction_handler.handle(instruction, pantry) + + pantry.add_substance(result) + + pantry.commit() + + return self._substance_schema.dump(result), 201 + + +def init_app(app): + class AppAlembicInstructionResource(AlembicInstructionResource, metaclass=ViewInjectorMeta): + get_app = lambda: app + + app.route('/alembic_instruction', endpoint='alembic_instruction')(AppAlembicInstructionResource) diff --git a/022-burette/magnum_opus_ii/magnumopus/resources/substance.py b/022-burette/magnum_opus_ii/magnumopus/resources/substance.py new file mode 100644 index 0000000..7c5ad88 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/resources/substance.py @@ -0,0 +1,49 @@ +from quart import request +from quart_openapi import Resource +from injector import inject +from typing import Dict +from ..injection import ViewInjectorMeta +from ..repositories.pantry import Pantry +from ..models import db +from ..models.substance import Substance +from ..schemas.substance_schema import SubstanceSchema + +class SubstanceResource(Resource): + @inject + def __init__(self, pantry: Pantry, substance_schemas: Dict[str, SubstanceSchema]): + super(SubstanceResource, self).__init__() + + self._pantry = pantry + self._substance_schema = substance_schemas['one'] + self._substances_schema = substance_schemas['many'] + + async def get(self): + nature = request.args.get('nature') + + substances = self._pantry.find_substances_by_nature(nature) + + return { + 'result': self._substances_schema.dump(substances) + } + + async def post(self): + args = await request.get_json() + + nature = args['nature'] + + pantry = self._pantry + + substance = Substance(nature=nature) + + pantry.add_substance(substance) + + pantry.commit() + + return self._substance_schema.dump(substance), 201 + + +def init_app(app): + class AppSubstanceResource(SubstanceResource, metaclass=ViewInjectorMeta): + get_app = lambda: app + + app.route('/substance', endpoint='SubstanceResource')(AppSubstanceResource) diff --git a/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py b/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py new file mode 100644 index 0000000..7b27dd7 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py @@ -0,0 +1,22 @@ +from typing import Dict +from flask_marshmallow import Marshmallow + +ma = Marshmallow() + +def init_app(app): + ma.init_app(app) + return [configure_injector] + +def configure_injector(binder): + from .substance_schema import SubstanceSchema + + binder.bind( + SubstanceSchema, to=SubstanceSchema() + ) + + binder.multibind( + Dict[str, SubstanceSchema], to={ + 'one': SubstanceSchema(), + 'many': SubstanceSchema(many=True) + } + ) diff --git a/022-burette/magnum_opus_ii/magnumopus/schemas/substance_schema.py b/022-burette/magnum_opus_ii/magnumopus/schemas/substance_schema.py new file mode 100644 index 0000000..3f86c70 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/schemas/substance_schema.py @@ -0,0 +1,19 @@ +from marshmallow import fields + +from . import ma + +from ..models.substance import Substance +from ..services.assessor import assess_whether_substance_is_philosophers_stone + +class SubstanceSchema(ma.SQLAlchemySchema): + is_philosophers_stone = fields.Function( + assess_whether_substance_is_philosophers_stone + ) + + class Meta: + model = Substance + fields = ('id', 'nature', 'is_philosophers_stone', 'state') + + id = fields.Integer() + nature = fields.String() + state = fields.Function(lambda model: model.state or []) diff --git a/022-burette/magnum_opus_ii/magnumopus/services/__init__.py b/022-burette/magnum_opus_ii/magnumopus/services/__init__.py new file mode 100644 index 0000000..561fd25 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/services/__init__.py @@ -0,0 +1,9 @@ +from .alembic import Alembic + +def init_app(app): + return [configure_injector] + +def configure_injector(binder): + binder.bind( + Alembic, to=Alembic + ) diff --git a/022-burette/magnum_opus_ii/magnumopus/services/alembic.py b/022-burette/magnum_opus_ii/magnumopus/services/alembic.py new file mode 100644 index 0000000..5fc05b2 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/services/alembic.py @@ -0,0 +1,51 @@ +from ..models.substance import Substance + +class NotEnoughSubstancesToMixException(Exception): + pass + +class UnknownProcessException(Exception): + pass + + +MIXTURES = { + ('Mercury', 'Salt', 'Sulphur'): 'Gloop' +} + + +class Alembic: + _nature_of_unknown_mixture = 'Sludge' + + @staticmethod + def _produce(nature): + return Substance(nature=nature) + + def mix(self, *substances): + if len(substances) < 2: + raise NotEnoughSubstancesToMixException() + + constituents = [substance.nature for substance in substances] + + # This gives us a canonical, ordered way of expressing our + # constituents that we can use as a recipe look-up + ingredient_list = tuple(sorted(constituents)) + + try: + nature = MIXTURES[ingredient_list] + except KeyError: + nature = self._nature_of_unknown_mixture + + return self._produce(nature) + + def process(self, process_name, substance): + if process_name == 'ferment': + result = substance.ferment() + elif process_name == 'cook': + result = substance.cook() + elif process_name == 'wash': + result = substance.wash() + elif process_name == 'pickle': + result = substance.pickle() + else: + raise UnknownProcessException() + + return result diff --git a/022-burette/magnum_opus_ii/magnumopus/services/alembic_instruction_handler.py b/022-burette/magnum_opus_ii/magnumopus/services/alembic_instruction_handler.py new file mode 100644 index 0000000..54fbb40 --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/services/alembic_instruction_handler.py @@ -0,0 +1,36 @@ +from dataclasses import dataclass +from injector import inject + +from .alembic import Alembic +from ..repositories.pantry import Pantry + +class UnknownAlembicInstructionException(Exception): + pass + +@dataclass +class AlembicInstruction: + instruction_type: str + natures: list + action: str = '' + +class AlembicInstructionHandler: + @inject + def handle(self, instruction: AlembicInstruction, pantry: Pantry): + natures = instruction.natures + action = instruction.action + instruction_type = instruction.instruction_type + + # Clearly need some validation here! + substances = [pantry.find_substances_by_nature(nature)[0] for nature in natures] + + alembic = Alembic() + + if instruction_type == 'mix': + result = alembic.mix(*substances) + elif instruction_type == 'process': + result = alembic.process(action, substances[0]) + else: + raise UnknownAlembicInstructionException(f'Unknown instruction: {action}') + + print(result.state, result.id, 'x') + return result diff --git a/022-burette/magnum_opus_ii/magnumopus/services/assessor.py b/022-burette/magnum_opus_ii/magnumopus/services/assessor.py new file mode 100644 index 0000000..94d564d --- /dev/null +++ b/022-burette/magnum_opus_ii/magnumopus/services/assessor.py @@ -0,0 +1,2 @@ +def assess_whether_substance_is_philosophers_stone(substance): + return substance.nature == 'Gloop' and substance.state == ['cooked', 'washed', 'pickled', 'fermented'] diff --git a/022-burette/magnum_opus_ii/pytestdebug.log b/022-burette/magnum_opus_ii/pytestdebug.log new file mode 100644 index 0000000..836541b --- /dev/null +++ b/022-burette/magnum_opus_ii/pytestdebug.log @@ -0,0 +1,4688 @@ +versions pytest-5.4.3, py-1.9.0, python-3.8.2.final.0 +cwd=/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii +args=('--debug',) + + pytest_cmdline_main [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_configure [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.LFPlugin object at 0x7f780666a820> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.NFPlugin object at 0x7f780666a9a0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + early skip of rewriting module: faulthandler [assertion] + pytest_configure [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_configure --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.faulthandler.FaultHandlerHooks object at 0x7f780666aa60> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.stepwise.StepwisePlugin object at 0x7f780666ab80> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + early skip of rewriting module: pdb [assertion] + early skip of rewriting module: cmd [assertion] + pytest_plugin_registered [hook] + plugin: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.config.Config object at 0x7f78089fd5b0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: > err=> in_=> _state='suspended' _in_suspended=False> _capture_fixture=None> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: testsfailed=0 testscollected=0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.LFPlugin object at 0x7f780666a820> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.NFPlugin object at 0x7f780666a9a0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.faulthandler.FaultHandlerHooks object at 0x7f780666aa60> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.stepwise.StepwisePlugin object at 0x7f780666ab80> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.terminal.TerminalReporter object at 0x7f780666aee0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.logging.LoggingPlugin object at 0x7f7806694820> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + finish pytest_configure --> [] [hook] + pytest_sessionstart [hook] + session: testsfailed=0 testscollected=0> + pytest_plugin_registered [hook] + plugin: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.config.Config object at 0x7f78089fd5b0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: > err=> in_=> _state='suspended' _in_suspended=False> _capture_fixture=None> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: testsfailed=0 testscollected=0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.LFPlugin object at 0x7f780666a820> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.NFPlugin object at 0x7f780666a9a0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.faulthandler.FaultHandlerHooks object at 0x7f780666aa60> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.stepwise.StepwisePlugin object at 0x7f780666ab80> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.terminal.TerminalReporter object at 0x7f780666aee0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.logging.LoggingPlugin object at 0x7f7806694820> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.fixtures.FixtureManager object at 0x7f7806694a60> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_report_header [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + startdir: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii + finish pytest_report_header --> [['rootdir: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii', 'plugins: pep8-1.0.6, asyncio-0.14.0, cov-2.10.0'], ['using: pytest-5.4.3 pylib-1.9.0', 'setuptools registered plugins:', ' pytest-pep8-1.0.6 at /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.env/lib/python3.8/site-packages/pytest_pep8.py', ' pytest-asyncio-0.14.0 at /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.env/lib/python3.8/site-packages/pytest_asyncio/plugin.py', ' pytest-cov-2.10.0 at /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.env/lib/python3.8/site-packages/pytest_cov/plugin.py']] [hook] + finish pytest_sessionstart --> [] [hook] + pytest_collection [hook] + session: testsfailed=0 testscollected=0> + perform_collect testsfailed=0 testscollected=0> ['/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii'] [collection] + pytest_collectstart [hook] + collector: testsfailed=0 testscollected=0> + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: testsfailed=0 testscollected=0> + processing argument (local('/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii'), []) [collection] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + early skip of rewriting module: py._code [assertion] + early skip of rewriting module: py._code.code [assertion] + early skip of rewriting module: repr [assertion] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.pytest_cache + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.env + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> True [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.tox + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.coverage + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.coverage + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.gitignore + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.gitignore + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/Dockerfile + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/Dockerfile + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/MANIFEST.in + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/MANIFEST.in + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/README.md + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/README.md + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/RULES.md + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/RULES.md + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker-compose.yml + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker-compose.yml + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/gunicorn_config.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/gunicorn_config.py + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/init_containers.sh + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/init_containers.sh + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/init_entrypoint.sh + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/init_entrypoint.sh + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/pytestdebug.log + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/pytestdebug.log + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/requirements.txt + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/requirements.txt + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/setup.cfg + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/setup.cfg + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/setup.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/setup.py + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tox.ini + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tox.ini + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/PKG-INFO + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/PKG-INFO + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/SOURCES.txt + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/SOURCES.txt + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/dependency_links.txt + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/dependency_links.txt + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/requires.txt + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/requires.txt + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/top_level.txt + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/top_level.txt + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker/storage + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker/storage + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker/storage/storage.db + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker/storage/storage.db + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/Pipfile + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/Pipfile + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/config.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/config.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/index.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/index.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/initialize.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/initialize.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/injection.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/injection.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/logger.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/logger.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/base.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/base.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/substance.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/substance.py + parent: + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/list_pantry.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/list_pantry.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/pantry.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/pantry.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/sqlalchemy_pantry.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/sqlalchemy_pantry.py + parent: + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/alembic_instruction.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/alembic_instruction.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/substance.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/substance.py + parent: + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/substance_schema.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/substance_schema.py + parent: + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/alembic.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/alembic.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/alembic_instruction_handler.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/alembic_instruction_handler.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/assessor.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/assessor.py + parent: + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/Pipfile + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/Pipfile + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/conftest.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/conftest.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/.coverage + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/.coverage + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/Pipfile + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/Pipfile + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + early skip of rewriting module: tests.application [assertion] + find_module called for: tests.application.test_alembic_instruction_resource [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py [assertion] + find_module called for: tests.application.test_substance_resource [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.application.test_alembic_instruction_resource + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.application + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.application.test_alembic_instruction_resource', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__pycache__/test_alembic_instruction_resource.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_app + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: is_dictionary_inside + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_substance_request + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_alembic_instruction_request + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_create_alembic_mix_instruction + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f78065e04c0> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_create_alembic_process_instruction + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806649640> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + find_module called for: tests.application.test_philosophers_stone [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.application.test_philosophers_stone + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.application + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.application.test_philosophers_stone', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__pycache__/test_philosophers_stone.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_app + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: is_dictionary_inside + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_create_philosophers_stone + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f78065e0fa0> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.application.test_substance_resource + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.application + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.application.test_substance_resource', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__pycache__/test_substance_resource.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_app + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: is_dictionary_inside + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_substance_request + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: index_substances_request + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_create_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f78065e04c0> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_get_substances + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f78065e0550> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + early skip of rewriting module: tests.domain [assertion] + find_module called for: tests.domain.test_alembic [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py [assertion] + early skip of rewriting module: magnumopus.services [assertion] + early skip of rewriting module: magnumopus.services.alembic [assertion] + early skip of rewriting module: magnumopus.models.substance [assertion] + early skip of rewriting module: sqlalchemy_utils [assertion] + early skip of rewriting module: sqlalchemy_utils.aggregates [assertion] + early skip of rewriting module: sqlalchemy_utils.functions [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.database [assertion] + early skip of rewriting module: sqlalchemy_utils.utils [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.orm [assertion] + early skip of rewriting module: sqlalchemy.ext.hybrid [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.foreign_keys [assertion] + early skip of rewriting module: sqlalchemy_utils.query_chain [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.mock [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.render [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.sort_query [assertion] + early skip of rewriting module: sqlalchemy_utils.relationships [assertion] + early skip of rewriting module: sqlalchemy_utils.relationships.chained_join [assertion] + early skip of rewriting module: sqlalchemy_utils.asserts [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.base [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.array [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.hstore [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.json [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.ranges [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.pg8000 [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.psycopg2 [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.psycopg2cffi [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.pygresql [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.pypostgresql [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.zxjdbc [assertion] + early skip of rewriting module: sqlalchemy.connectors [assertion] + early skip of rewriting module: sqlalchemy.connectors.zxJDBC [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.dml [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.ext [assertion] + early skip of rewriting module: sqlalchemy_utils.exceptions [assertion] + early skip of rewriting module: sqlalchemy_utils.expressions [assertion] + early skip of rewriting module: sqlalchemy.ext.compiler [assertion] + early skip of rewriting module: sqlalchemy_utils.generic [assertion] + early skip of rewriting module: sqlalchemy_utils.i18n [assertion] + early skip of rewriting module: babel [assertion] + early skip of rewriting module: sqlalchemy_utils.listeners [assertion] + early skip of rewriting module: sqlalchemy_utils.models [assertion] + early skip of rewriting module: sqlalchemy_utils.observer [assertion] + early skip of rewriting module: sqlalchemy_utils.path [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives.country [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives.currency [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives.ltree [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives.weekday [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives.weekdays [assertion] + early skip of rewriting module: sqlalchemy_utils.proxy_dict [assertion] + early skip of rewriting module: sqlalchemy_utils.types [assertion] + early skip of rewriting module: sqlalchemy_utils.types.arrow [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime.arrow_datetime [assertion] + early skip of rewriting module: arrow [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime.pendulum_date [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime.pendulum_datetime [assertion] + early skip of rewriting module: pendulum [assertion] + early skip of rewriting module: pendulum [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime.enriched_datetime_type [assertion] + early skip of rewriting module: sqlalchemy_utils.types.scalar_coercible [assertion] + early skip of rewriting module: arrow [assertion] + early skip of rewriting module: sqlalchemy_utils.types.choice [assertion] + early skip of rewriting module: sqlalchemy_utils.types.color [assertion] + early skip of rewriting module: colour [assertion] + early skip of rewriting module: sqlalchemy_utils.types.country [assertion] + early skip of rewriting module: sqlalchemy_utils.types.currency [assertion] + early skip of rewriting module: sqlalchemy_utils.types.email [assertion] + early skip of rewriting module: sqlalchemy_utils.operators [assertion] + early skip of rewriting module: sqlalchemy_utils.types.encrypted [assertion] + early skip of rewriting module: sqlalchemy_utils.types.encrypted.encrypted_type [assertion] + early skip of rewriting module: sqlalchemy_utils.types.encrypted.padding [assertion] + early skip of rewriting module: sqlalchemy_utils.types.json [assertion] + early skip of rewriting module: anyjson [assertion] + early skip of rewriting module: cryptography [assertion] + early skip of rewriting module: dateutil [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime.enriched_date_type [assertion] + early skip of rewriting module: sqlalchemy_utils.types.ip_address [assertion] + early skip of rewriting module: ipaddress [assertion] + early skip of rewriting module: sqlalchemy_utils.types.locale [assertion] + early skip of rewriting module: babel [assertion] + early skip of rewriting module: sqlalchemy_utils.types.ltree [assertion] + early skip of rewriting module: sqlalchemy_utils.types.password [assertion] + early skip of rewriting module: sqlalchemy.dialects.oracle [assertion] + early skip of rewriting module: sqlalchemy.dialects.oracle.base [assertion] + early skip of rewriting module: sqlalchemy.dialects.oracle.cx_oracle [assertion] + early skip of rewriting module: sqlalchemy.dialects.oracle.zxjdbc [assertion] + early skip of rewriting module: sqlalchemy.dialects.sqlite [assertion] + early skip of rewriting module: sqlalchemy.dialects.sqlite.base [assertion] + early skip of rewriting module: sqlalchemy.dialects.sqlite.json [assertion] + early skip of rewriting module: sqlalchemy.dialects.sqlite.pysqlcipher [assertion] + early skip of rewriting module: sqlalchemy.dialects.sqlite.pysqlite [assertion] + early skip of rewriting module: sqlalchemy.ext.mutable [assertion] + early skip of rewriting module: passlib [assertion] + early skip of rewriting module: sqlalchemy_utils.types.pg_composite [assertion] + early skip of rewriting module: psycopg2 [assertion] + early skip of rewriting module: sqlalchemy_utils.types.phone_number [assertion] + early skip of rewriting module: phonenumbers [assertion] + early skip of rewriting module: sqlalchemy_utils.types.range [assertion] + early skip of rewriting module: intervals [assertion] + early skip of rewriting module: sqlalchemy_utils.types.scalar_list [assertion] + early skip of rewriting module: sqlalchemy_utils.types.timezone [assertion] + early skip of rewriting module: sqlalchemy_utils.types.ts_vector [assertion] + early skip of rewriting module: sqlalchemy_utils.types.url [assertion] + early skip of rewriting module: furl [assertion] + early skip of rewriting module: sqlalchemy_utils.types.uuid [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.adodbapi [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.base [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.information_schema [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.mxodbc [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.pyodbc [assertion] + early skip of rewriting module: sqlalchemy.connectors.pyodbc [assertion] + early skip of rewriting module: sqlalchemy.connectors.mxodbc [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.pymssql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.zxjdbc [assertion] + early skip of rewriting module: sqlalchemy_utils.types.weekdays [assertion] + early skip of rewriting module: sqlalchemy_utils.types.bit [assertion] + early skip of rewriting module: sqlalchemy_utils.view [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.domain.test_alembic + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.domain + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.domain.test_alembic', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__pycache__/test_alembic.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: Alembic + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: NotEnoughSubstancesToMixException + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: UnknownProcessException + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: Substance + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_set_up_my_alembic + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_mix_multiple_substances_in_my_alembic + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_cannot_mix_one_substance_in_my_alembic + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_mixing_sulphur_salt_and_mercury_gives_gloop + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_mixing_other_recipes_gives_sludge + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_process_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_cannot_perform_unknown_process + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + find_module called for: tests.domain.test_alembic_instruction_handler [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py [assertion] + early skip of rewriting module: magnumopus.services.alembic_instruction_handler [assertion] + early skip of rewriting module: injector [assertion] + early skip of rewriting module: magnumopus.repositories [assertion] + early skip of rewriting module: magnumopus.repositories.pantry [assertion] + early skip of rewriting module: magnumopus.repositories.list_pantry [assertion] + early skip of rewriting module: magnumopus.repositories.sqlalchemy_pantry [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.domain.test_alembic_instruction_handler + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.domain + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.domain.test_alembic_instruction_handler', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__pycache__/test_alembic_instruction_handler.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: AlembicInstruction + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: AlembicInstructionHandler + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: ListPantry + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: Substance + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: instruction_unknown + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: instruction + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pantry + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_set_up_my_alembic_instruction_handler + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325040> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + find_module called for: tests.domain.test_pantry [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.domain.test_pantry + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.domain + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.domain.test_pantry', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__pycache__/test_pantry.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: ListPantry + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: Substance + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: list_pantry + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pantries + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_add_to_pantry + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f78063257f0> + pytest_make_parametrize_id [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + val: list + argname: pantry_type + finish pytest_make_parametrize_id --> None [hook] + early skip of rewriting module: encodings.unicode_escape [assertion] + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_retrieve_substance_from_pantry_by_nature + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325670> + pytest_make_parametrize_id [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + val: list + argname: pantry_type + finish pytest_make_parametrize_id --> None [hook] + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + find_module called for: tests.domain.test_substance [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.domain.test_substance + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.domain + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.domain.test_substance', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__pycache__/test_substance.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: Substance + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_cook_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_wash_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_pickle_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_ferment_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_cook_and_ferment_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_the_order_of_processes_applied_to_a_substance_matters + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + pytest_collection_modifyitems [hook] + session: testsfailed=0 testscollected=0> + config: <_pytest.config.Config object at 0x7f78089fd5b0> + items: [, , , , , , , , , , , , , , , , , , , , ] + finish pytest_collection_modifyitems --> [] [hook] + pytest_collection_finish [hook] + session: testsfailed=0 testscollected=0> + pytest_report_collectionfinish [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + startdir: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii + items: [, , , , , , , , , , , , , , , , , , , , ] + finish pytest_report_collectionfinish --> [] [hook] + finish pytest_collection_finish --> [] [hook] + finish pytest_collection --> [, , , , , , , , , , , , , , , , , , , , ] [hook] + pytest_runtestloop [hook] + session: testsfailed=0 testscollected=21> + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/application/test_alembic_instruction_resource.py::test_create_alembic_mix_instruction + location: ('tests/application/test_alembic_instruction_resource.py', 16, 'test_create_alembic_mix_instruction') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> <_UnixSelectorEventLoop running=False closed=False debug=False> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + early skip of rewriting module: magnumopus.resources [assertion] + early skip of rewriting module: magnumopus.resources.substance [assertion] + early skip of rewriting module: magnumopus.injection [assertion] + early skip of rewriting module: magnumopus.schemas [assertion] + early skip of rewriting module: flask_marshmallow [assertion] + early skip of rewriting module: distutils [assertion] + early skip of rewriting module: distutils.version [assertion] + early skip of rewriting module: marshmallow [assertion] + early skip of rewriting module: marshmallow.schema [assertion] + early skip of rewriting module: marshmallow.base [assertion] + early skip of rewriting module: marshmallow.fields [assertion] + early skip of rewriting module: marshmallow.validate [assertion] + early skip of rewriting module: marshmallow.types [assertion] + early skip of rewriting module: marshmallow.exceptions [assertion] + early skip of rewriting module: marshmallow.utils [assertion] + early skip of rewriting module: marshmallow.class_registry [assertion] + early skip of rewriting module: marshmallow.error_store [assertion] + early skip of rewriting module: marshmallow.orderedset [assertion] + early skip of rewriting module: marshmallow.decorators [assertion] + early skip of rewriting module: flask_marshmallow.fields [assertion] + early skip of rewriting module: flask_marshmallow.schema [assertion] + early skip of rewriting module: flask_marshmallow.compat [assertion] + early skip of rewriting module: flask_marshmallow.sqla [assertion] + early skip of rewriting module: six.moves.urllib [assertion] + early skip of rewriting module: marshmallow_sqlalchemy [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema.model_schema [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.convert [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.base [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.reflection [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.enumerated [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.types [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.json [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.cymysql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.mysqldb [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.gaerdbms [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.mysqlconnector [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.oursql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.pymysql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.pyodbc [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.zxjdbc [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.dml [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.exceptions [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.fields [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema.schema_meta [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema.load_instance_mixin [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema.table_schema [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema.sqlalchemy_schema [assertion] + early skip of rewriting module: magnumopus.schemas.substance_schema [assertion] + early skip of rewriting module: magnumopus.services.assessor [assertion] + early skip of rewriting module: magnumopus.resources.alembic_instruction [assertion] + early skip of rewriting module: magnumopus.logger [assertion] + early skip of rewriting module: magnumopus.config [assertion] + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + pytest_assertrepr_compare [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + op: == + left: 500 + right: 201 + finish pytest_assertrepr_compare --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: > + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_exception_interact [hook] + node: + call: > + report: + finish pytest_exception_interact --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/application/test_alembic_instruction_resource.py::test_create_alembic_mix_instruction + location: ('tests/application/test_alembic_instruction_resource.py', 16, 'test_create_alembic_mix_instruction') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/application/test_alembic_instruction_resource.py::test_create_alembic_process_instruction + location: ('tests/application/test_alembic_instruction_resource.py', 34, 'test_create_alembic_process_instruction') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> <_UnixSelectorEventLoop running=False closed=False debug=False> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + pytest_assertrepr_compare [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + op: == + left: 500 + right: 201 + finish pytest_assertrepr_compare --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: > + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_exception_interact [hook] + node: + call: > + report: + finish pytest_exception_interact --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/application/test_alembic_instruction_resource.py::test_create_alembic_process_instruction + location: ('tests/application/test_alembic_instruction_resource.py', 34, 'test_create_alembic_process_instruction') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/application/test_philosophers_stone.py::test_create_philosophers_stone + location: ('tests/application/test_philosophers_stone.py', 5, 'test_create_philosophers_stone') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> <_UnixSelectorEventLoop running=False closed=False debug=False> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/application/test_philosophers_stone.py::test_create_philosophers_stone + location: ('tests/application/test_philosophers_stone.py', 5, 'test_create_philosophers_stone') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/application/test_substance_resource.py::test_create_substance + location: ('tests/application/test_substance_resource.py', 12, 'test_create_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> <_UnixSelectorEventLoop running=False closed=False debug=False> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/application/test_substance_resource.py::test_create_substance + location: ('tests/application/test_substance_resource.py', 12, 'test_create_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/application/test_substance_resource.py::test_get_substances + location: ('tests/application/test_substance_resource.py', 29, 'test_get_substances') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> <_UnixSelectorEventLoop running=False closed=False debug=False> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + pytest_assertrepr_compare [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + op: is + left: + right: + finish pytest_assertrepr_compare --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: is list\n + where = type(None)") tblen=31>> + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_exception_interact [hook] + node: + call: is list\n + where = type(None)") tblen=1>> + report: + finish pytest_exception_interact --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/application/test_substance_resource.py::test_get_substances + location: ('tests/application/test_substance_resource.py', 29, 'test_get_substances') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_can_set_up_my_alembic + location: ('tests/domain/test_alembic.py', 5, 'test_can_set_up_my_alembic') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_can_set_up_my_alembic + location: ('tests/domain/test_alembic.py', 5, 'test_can_set_up_my_alembic') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_can_mix_multiple_substances_in_my_alembic + location: ('tests/domain/test_alembic.py', 8, 'test_can_mix_multiple_substances_in_my_alembic') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_can_mix_multiple_substances_in_my_alembic + location: ('tests/domain/test_alembic.py', 8, 'test_can_mix_multiple_substances_in_my_alembic') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_cannot_mix_one_substance_in_my_alembic + location: ('tests/domain/test_alembic.py', 16, 'test_cannot_mix_one_substance_in_my_alembic') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_cannot_mix_one_substance_in_my_alembic + location: ('tests/domain/test_alembic.py', 16, 'test_cannot_mix_one_substance_in_my_alembic') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_mixing_sulphur_salt_and_mercury_gives_gloop + location: ('tests/domain/test_alembic.py', 23, 'test_mixing_sulphur_salt_and_mercury_gives_gloop') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_mixing_sulphur_salt_and_mercury_gives_gloop + location: ('tests/domain/test_alembic.py', 23, 'test_mixing_sulphur_salt_and_mercury_gives_gloop') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_mixing_other_recipes_gives_sludge + location: ('tests/domain/test_alembic.py', 38, 'test_mixing_other_recipes_gives_sludge') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_mixing_other_recipes_gives_sludge + location: ('tests/domain/test_alembic.py', 38, 'test_mixing_other_recipes_gives_sludge') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_can_process_substance + location: ('tests/domain/test_alembic.py', 58, 'test_can_process_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_can_process_substance + location: ('tests/domain/test_alembic.py', 58, 'test_can_process_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_cannot_perform_unknown_process + location: ('tests/domain/test_alembic.py', 74, 'test_cannot_perform_unknown_process') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_cannot_perform_unknown_process + location: ('tests/domain/test_alembic.py', 74, 'test_cannot_perform_unknown_process') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic_instruction_handler.py::test_can_set_up_my_alembic_instruction_handler + location: ('tests/domain/test_alembic_instruction_handler.py', 34, 'test_can_set_up_my_alembic_instruction_handler') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> AlembicInstruction(instruction_type='process', natures=['Sludge'], action='cook') [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic_instruction_handler.py::test_can_set_up_my_alembic_instruction_handler + location: ('tests/domain/test_alembic_instruction_handler.py', 34, 'test_can_set_up_my_alembic_instruction_handler') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_pantry.py::test_can_add_to_pantry[list] + location: ('tests/domain/test_pantry.py', 17, 'test_can_add_to_pantry[list]') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> list [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + list: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_pantry.py::test_can_add_to_pantry[list] + location: ('tests/domain/test_pantry.py', 17, 'test_can_add_to_pantry[list]') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_pantry.py::test_can_retrieve_substance_from_pantry_by_nature[list] + location: ('tests/domain/test_pantry.py', 27, 'test_can_retrieve_substance_from_pantry_by_nature[list]') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> list [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + list: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_pantry.py::test_can_retrieve_substance_from_pantry_by_nature[list] + location: ('tests/domain/test_pantry.py', 27, 'test_can_retrieve_substance_from_pantry_by_nature[list]') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_can_cook_substance + location: ('tests/domain/test_substance.py', 2, 'test_can_cook_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_can_cook_substance + location: ('tests/domain/test_substance.py', 2, 'test_can_cook_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_can_wash_substance + location: ('tests/domain/test_substance.py', 9, 'test_can_wash_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_can_wash_substance + location: ('tests/domain/test_substance.py', 9, 'test_can_wash_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_can_pickle_substance + location: ('tests/domain/test_substance.py', 16, 'test_can_pickle_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_can_pickle_substance + location: ('tests/domain/test_substance.py', 16, 'test_can_pickle_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_can_ferment_substance + location: ('tests/domain/test_substance.py', 23, 'test_can_ferment_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_can_ferment_substance + location: ('tests/domain/test_substance.py', 23, 'test_can_ferment_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_can_cook_and_ferment_substance + location: ('tests/domain/test_substance.py', 30, 'test_can_cook_and_ferment_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_can_cook_and_ferment_substance + location: ('tests/domain/test_substance.py', 30, 'test_can_cook_and_ferment_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: None + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_the_order_of_processes_applied_to_a_substance_matters + location: ('tests/domain/test_substance.py', 38, 'test_the_order_of_processes_applied_to_a_substance_matters') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: None + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_the_order_of_processes_applied_to_a_substance_matters + location: ('tests/domain/test_substance.py', 38, 'test_the_order_of_processes_applied_to_a_substance_matters') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + finish pytest_runtestloop --> True [hook] + pytest_sessionfinish [hook] + session: testsfailed=3 testscollected=21> + exitstatus: ExitCode.TESTS_FAILED + pytest_terminal_summary [hook] + terminalreporter: <_pytest.terminal.TerminalReporter object at 0x7f780666aee0> + exitstatus: ExitCode.TESTS_FAILED + config: <_pytest.config.Config object at 0x7f78089fd5b0> + early skip of rewriting module: pygments [assertion] + early skip of rewriting module: pygments [assertion] + early skip of rewriting module: pygments [assertion] + early skip of rewriting module: wcwidth [assertion] + early skip of rewriting module: wcwidth.wcwidth [assertion] + early skip of rewriting module: wcwidth.table_wide [assertion] + early skip of rewriting module: wcwidth.table_zero [assertion] + early skip of rewriting module: wcwidth.unicode_versions [assertion] + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + finish pytest_terminal_summary --> [] [hook] + finish pytest_sessionfinish --> [] [hook] + pytest_unconfigure [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_unconfigure --> [] [hook] diff --git a/022-burette/magnum_opus_ii/requirements.txt b/022-burette/magnum_opus_ii/requirements.txt new file mode 100644 index 0000000..0104ae5 --- /dev/null +++ b/022-burette/magnum_opus_ii/requirements.txt @@ -0,0 +1,9 @@ +appdirs +quart +wheel +quart-openapi +flask-marshmallow +flask-sqlalchemy +flask-injector +marshmallow-sqlalchemy +sqlalchemy-utils diff --git a/022-burette/magnum_opus_ii/setup.cfg b/022-burette/magnum_opus_ii/setup.cfg new file mode 100644 index 0000000..74b608f --- /dev/null +++ b/022-burette/magnum_opus_ii/setup.cfg @@ -0,0 +1,34 @@ +[metadata] +name = aiomagnumopus +version = 0.0.1 +author = Phil Weir +author_email = phil.weir@flaxandteal.co.uk +license = GPL +description = Service for cooking up a philosopher's stone +long-description = file:README.md + +[options] +include_package_data = True +packages = find: +python_requires = >=3.6 +install_requires = + appdirs + quart-openapi + flask-marshmallow + flask-sqlalchemy + flask-injector + sqlalchemy-utils + marshmallow-sqlalchemy + quart-openapi + wheel + +[options.extras_require] +dev = + pytest + pytest-pep8 + pytest-cov + pytest-asyncio + +[options.packages.find] +exclude = + tests diff --git a/022-burette/magnum_opus_ii/setup.py b/022-burette/magnum_opus_ii/setup.py new file mode 100644 index 0000000..1767837 --- /dev/null +++ b/022-burette/magnum_opus_ii/setup.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +""" +Magnum Opus + +This tool performs alchemical reactions to create +the Philosopher's Stone. + +@author: Phil Weir +""" + +from setuptools import setup + +if __name__ == '__main__': + setup() diff --git a/022-burette/magnum_opus_ii/tests/__init__.py b/022-burette/magnum_opus_ii/tests/__init__.py new file mode 100644 index 0000000..c09f99d --- /dev/null +++ b/022-burette/magnum_opus_ii/tests/__init__.py @@ -0,0 +1,4 @@ + +def is_dictionary_inside(d1, d2): + return d1.items() <= d2.items() + diff --git a/022-burette/magnum_opus_ii/tests/application/.coverage b/022-burette/magnum_opus_ii/tests/application/.coverage new file mode 100644 index 0000000..0e5750b Binary files /dev/null and b/022-burette/magnum_opus_ii/tests/application/.coverage differ diff --git a/022-burette/magnum_opus_ii/tests/application/__init__.py b/022-burette/magnum_opus_ii/tests/application/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py b/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py new file mode 100644 index 0000000..d7c7c14 --- /dev/null +++ b/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py @@ -0,0 +1,49 @@ +import pytest +from magnumopus import create_app +from .. import is_dictionary_inside +from .test_substance_resource import create_substance_request + +async def create_alembic_instruction_request(client, instruction_type, natures, action=None): + data = { + 'instruction_type': instruction_type, + 'natures': ','.join(natures) + } + + if action is not None: + data['action'] = action + + return await client.post('/alembic_instruction', json=data) + +@pytest.mark.asyncio +async def test_create_alembic_mix_instruction(client): + await create_substance_request(client, 'Mercury') + await create_substance_request(client, 'Salt') + await create_substance_request(client, 'Sulphur') + + rv = await create_alembic_instruction_request(client, 'mix', ['Mercury', 'Salt', 'Sulphur']) + + assert rv.status_code == 201 + + content = await rv.get_json() + + assert is_dictionary_inside({ + 'nature': 'Gloop', + 'state': [], + 'is_philosophers_stone': False + }, content) + +@pytest.mark.asyncio +async def test_create_alembic_process_instruction(client): + await create_substance_request(client, 'Mercury') + + rv = await create_alembic_instruction_request(client, 'process', ['Mercury'], 'cook') + + assert rv.status_code == 201 + + content = await rv.get_json() + + assert is_dictionary_inside({ + 'nature': 'Mercury', + 'state': ['cooked'], + 'is_philosophers_stone': False + }, content) diff --git a/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py b/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py new file mode 100644 index 0000000..ca25fb7 --- /dev/null +++ b/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py @@ -0,0 +1,7 @@ +import pytest +from magnumopus import create_app +from .. import is_dictionary_inside + + +def test_create_philosophers_stone(client): + pass diff --git a/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py b/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py new file mode 100644 index 0000000..28a8ec7 --- /dev/null +++ b/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py @@ -0,0 +1,52 @@ +import pytest +from magnumopus import create_app +from .. import is_dictionary_inside + +async def create_substance_request(client, nature): + return await client.post('/substance', json={ + 'nature': nature + }) + +async def index_substances_request(client, nature): + return await client.get(f'/substance?nature={nature}') + +@pytest.mark.asyncio +async def test_create_substance(client): + rv = await create_substance_request(client, 'Sulphur') + + assert rv.status_code == 201 + + content = await rv.get_json() + + assert type(content['id']) is int + + assert is_dictionary_inside({ + 'nature': 'Sulphur', + 'state': [], + 'is_philosophers_stone': False + }, content) + + +@pytest.mark.asyncio +async def test_get_substances(client): + await create_substance_request(client, 'Sulphur') + + rv = await index_substances_request(client, 'Sulphur') + + assert rv.status_code == 200 + + content = (await rv.get_json())['result'] + + assert type(content) is list + + assert len(content) == 1 + + assert type(content[0]['id']) is int + + assert is_dictionary_inside({ + 'nature': 'Sulphur', + 'state': [], + 'is_philosophers_stone': False + }, content[0]) + +# We also need non-happy paths! diff --git a/022-burette/magnum_opus_ii/tests/conftest.py b/022-burette/magnum_opus_ii/tests/conftest.py new file mode 100644 index 0000000..d810697 --- /dev/null +++ b/022-burette/magnum_opus_ii/tests/conftest.py @@ -0,0 +1,19 @@ +import pytest +from magnumopus import create_app +from magnumopus.repositories.pantry import Pantry + +@pytest.fixture +async def app(): + app = create_app() + await app.startup() + yield app + await app.shutdown() + + +@pytest.fixture +async def client(app): + pantry = app.extensions['injector'].get(Pantry) + pantry.empty_pantry() + async with app.test_client() as client: + yield client + pantry.empty_pantry() diff --git a/022-burette/magnum_opus_ii/tests/domain/__init__.py b/022-burette/magnum_opus_ii/tests/domain/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/022-burette/magnum_opus_ii/tests/domain/test_alembic.py b/022-burette/magnum_opus_ii/tests/domain/test_alembic.py new file mode 100644 index 0000000..cd67657 --- /dev/null +++ b/022-burette/magnum_opus_ii/tests/domain/test_alembic.py @@ -0,0 +1,81 @@ +import pytest + +from magnumopus.services.alembic import Alembic, NotEnoughSubstancesToMixException, UnknownProcessException +from magnumopus.models.substance import Substance + +def test_can_set_up_my_alembic(): + Alembic() + +def test_can_mix_multiple_substances_in_my_alembic(): + alembic = Alembic() + substance = [Substance() for _ in range(3)] + alembic.mix(*substance) + + substance = [Substance() for _ in range(6)] + alembic.mix(*substance) + +def test_cannot_mix_one_substance_in_my_alembic(): + alembic = Alembic() + substance = Substance() + + with pytest.raises(NotEnoughSubstancesToMixException): + alembic.mix(substance) + +def test_mixing_sulphur_salt_and_mercury_gives_gloop(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + + result = alembic.mix(sulphur, salt, mercury) + + assert result.nature == 'Gloop' + + result = alembic.mix(mercury, sulphur, salt) + + assert result.nature == 'Gloop' + +def test_mixing_other_recipes_gives_sludge(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + gloop = Substance(nature='Gloop') + + result = alembic.mix(sulphur, salt, mercury, sulphur) + + assert result.nature == 'Sludge' + + result = alembic.mix(salt, mercury) + + assert result.nature == 'Sludge' + + result = alembic.mix(gloop, salt, mercury) + + assert result.nature == 'Sludge' + +def test_can_process_substance(): + alembic = Alembic() + + substance = Substance() + result = alembic.process('cook', substance) + + substance = Substance() + cooked_substance = substance.cook() + + assert result.state == cooked_substance.state + + result = alembic.process('ferment', substance) + cooked_fermented_substance = cooked_substance.ferment() + + assert result.state == cooked_fermented_substance.state + +def test_cannot_perform_unknown_process(): + alembic = Alembic() + + substance = Substance() + + with pytest.raises(UnknownProcessException): + alembic.process('boil', substance) diff --git a/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py b/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py new file mode 100644 index 0000000..ccb2f96 --- /dev/null +++ b/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py @@ -0,0 +1,37 @@ +import pytest + +from magnumopus.services.alembic_instruction_handler import AlembicInstruction, AlembicInstructionHandler +from magnumopus.repositories.list_pantry import ListPantry +from magnumopus.models.substance import Substance + +@pytest.fixture +def instruction_unknown(): + return AlembicInstruction( + 'saute', + ['Sulphur'], + 'cook' + ) + +@pytest.fixture +def instruction(): + return AlembicInstruction( + 'process', + ['Sludge'], + 'cook' + ) + +@pytest.fixture +def pantry(): + pantry = ListPantry() + + substance = Substance(nature='Sludge') + pantry.add_substance(substance) + + substance = Substance(nature='Sulphur') + pantry.add_substance(substance) + + return pantry + +def test_can_set_up_my_alembic_instruction_handler(instruction, pantry): + handler = AlembicInstructionHandler() + handler.handle(instruction, pantry) diff --git a/022-burette/magnum_opus_ii/tests/domain/test_pantry.py b/022-burette/magnum_opus_ii/tests/domain/test_pantry.py new file mode 100644 index 0000000..0dc5010 --- /dev/null +++ b/022-burette/magnum_opus_ii/tests/domain/test_pantry.py @@ -0,0 +1,38 @@ +import pytest + +from magnumopus.repositories.list_pantry import ListPantry +from magnumopus.models.substance import Substance + +@pytest.fixture +def list_pantry(): + return ListPantry() + +@pytest.fixture +@pytest.mark.asyncio +def pantries(list_pantry): + return { + 'list': list_pantry + } + +# We may want other pantry-specific tests, but bear in mind LSP +@pytest.mark.parametrize('pantry_type', ['list']) +def test_can_add_to_pantry(pantry_type, pantries): + pantry = pantries[pantry_type] + + substance = Substance() + + pantry.add_substance(substance) + + assert pantry.count_all_substances() == 1 + +@pytest.mark.parametrize('pantry_type', ['list']) +def test_can_retrieve_substance_from_pantry_by_nature(pantry_type, pantries): + pantry = pantries[pantry_type] + + substance = Substance(nature='Mercury') + + pantry.add_substance(substance) + + mercury = pantry.find_substances_by_nature('Mercury')[0] + + assert mercury.nature == 'Mercury' diff --git a/022-burette/magnum_opus_ii/tests/domain/test_substance.py b/022-burette/magnum_opus_ii/tests/domain/test_substance.py new file mode 100644 index 0000000..d00a6f7 --- /dev/null +++ b/022-burette/magnum_opus_ii/tests/domain/test_substance.py @@ -0,0 +1,49 @@ +from magnumopus.models.substance import Substance + +def test_can_cook_substance(): + substance = Substance() + + result = substance.cook() + + assert substance.state == ['cooked'] + +def test_can_wash_substance(): + substance = Substance() + + result = substance.wash() + + assert result.state == ['washed'] + +def test_can_pickle_substance(): + substance = Substance() + + result = substance.pickle() + + assert result.state == ['pickled'] + +def test_can_ferment_substance(): + substance = Substance() + + result = substance.ferment() + + assert substance.state == ['fermented'] + +def test_can_cook_and_ferment_substance(): + substance = Substance() + + result = substance.cook() + result = result.ferment() + + assert substance.state == ['cooked', 'fermented'] + +def test_the_order_of_processes_applied_to_a_substance_matters(): + substance1 = Substance() + result1 = substance1.cook() + result1 = result1.ferment() + + substance2 = Substance() + result2 = substance2.ferment() + result2 = result2.cook() + + assert result1.state != result2.state + assert result1.state == result2.state[::-1] diff --git a/022-burette/magnum_opus_ii/tox.ini b/022-burette/magnum_opus_ii/tox.ini new file mode 100644 index 0000000..d815853 --- /dev/null +++ b/022-burette/magnum_opus_ii/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist = py38 + +[testenv] +deps = pytest +commands = pytest diff --git a/022-burette/magnum_opus_iii/.coverage b/022-burette/magnum_opus_iii/.coverage new file mode 100644 index 0000000..acffb03 Binary files /dev/null and b/022-burette/magnum_opus_iii/.coverage differ diff --git a/022-burette/magnum_opus_iii/.gitignore b/022-burette/magnum_opus_iii/.gitignore new file mode 100644 index 0000000..1069b36 --- /dev/null +++ b/022-burette/magnum_opus_iii/.gitignore @@ -0,0 +1,5 @@ +*.egg-info +.tox +Pipfile +.env +.nenv diff --git a/022-burette/magnum_opus_iii/Dockerfile b/022-burette/magnum_opus_iii/Dockerfile new file mode 100644 index 0000000..0c7c8cf --- /dev/null +++ b/022-burette/magnum_opus_iii/Dockerfile @@ -0,0 +1,24 @@ +FROM python:3-alpine + +RUN addgroup -S user && adduser user -S -G user + +WORKDIR /home/user/ + +COPY requirements.txt . +COPY gunicorn_config.py . +COPY setup.py . +COPY setup.cfg . +COPY init_entrypoint.sh / + +RUN pip install hypercorn +RUN pip install -r requirements.txt + +USER user + +EXPOSE 5000 + +ENTRYPOINT [] + +CMD hypercorn --config python:./gunicorn_config.py magnumopus.index:app + +COPY magnumopus magnumopus diff --git a/022-burette/magnum_opus_iii/MANIFEST.in b/022-burette/magnum_opus_iii/MANIFEST.in new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/022-burette/magnum_opus_iii/MANIFEST.in @@ -0,0 +1 @@ + diff --git a/022-burette/magnum_opus_iii/README.md b/022-burette/magnum_opus_iii/README.md new file mode 100644 index 0000000..94ce180 --- /dev/null +++ b/022-burette/magnum_opus_iii/README.md @@ -0,0 +1,46 @@ +Magnum Opus +=========== + +Recipe maker for the philosopher's stone. + + + python3 -m pytest --cov magnumopus >> README.md + + ============================= test session starts ============================== + platform linux -- Python 3.8.2, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 + rootdir: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus + plugins: pep8-1.0.6, cov-2.10.0 + collected 15 items + + tests/domain/test_alembic.py ....... [ 46%] + tests/domain/test_pantry.py .. [ 60%] + tests/domain/test_substance.py ...... [100%] + + ----------- coverage: platform linux, python 3.8.2-final-0 ----------- + Name Stmts Miss Cover + ------------------------------------------------------------------------ + magnumopus/__init__.py 10 8 20% + magnumopus/config.py 4 4 0% + magnumopus/index.py 2 2 0% + magnumopus/initialize.py 6 6 0% + magnumopus/logger.py 4 4 0% + magnumopus/models/__init__.py 3 1 67% + magnumopus/models/base.py 2 0 100% + magnumopus/models/substance.py 24 0 100% + magnumopus/repositories/__init__.py 0 0 100% + magnumopus/repositories/pantry.py 12 1 92% + magnumopus/repositories/sqlalchemy_pantry.py 15 15 0% + magnumopus/resources/__init__.py 7 7 0% + magnumopus/resources/alembic_instruction.py 26 26 0% + magnumopus/resources/substance.py 28 28 0% + magnumopus/schemas/__init__.py 4 4 0% + magnumopus/schemas/substance_schema.py 11 11 0% + magnumopus/services/__init__.py 0 0 100% + magnumopus/services/alembic.py 32 2 94% + magnumopus/services/alembic_instruction_handler.py 20 20 0% + magnumopus/services/assessor.py 2 2 0% + ------------------------------------------------------------------------ + TOTAL 212 141 33% + + + ============================== 15 passed in 0.38s ============================== diff --git a/022-burette/magnum_opus_iii/RULES.md b/022-burette/magnum_opus_iii/RULES.md new file mode 100644 index 0000000..4438311 --- /dev/null +++ b/022-burette/magnum_opus_iii/RULES.md @@ -0,0 +1,9 @@ +* One unit of each of the substances Mercury, Salt and Sulphur are mixed, using my "Alembic" (mixing pot), giving one unit of another substance, Gloop +* Any attempt to mix anything other than those three substances, gives Sludge, another substance +* Substances can undergo several Processes in my Alembic - they can be Cooked, Washed, Pickled or Fermented +* If Gloop is Cooked, Washed, Pickled and Fermented, in that order, it is the Philosopher's Stone (panacea and cure of all ills) +[* To process a Substance, at least one unit must be in my Pantry, including Gloop - even when freshly processed/created, it must be stored there before re-use (to cool)] + +Final rule: +GROUP 1: When I process a substance, using any process, it becomes a different substance +GROUP 2: When I process a substance, its state changes but is essentially the same substance (NB: mixing is not a process) diff --git a/022-burette/magnum_opus_iii/docker-compose.yml b/022-burette/magnum_opus_iii/docker-compose.yml new file mode 100644 index 0000000..8dd5ffa --- /dev/null +++ b/022-burette/magnum_opus_iii/docker-compose.yml @@ -0,0 +1,11 @@ +version: "3" +services: + web_async_gql: + build: . + environment: + DATABASE_URI: 'sqlite:////docker/storage/storage.db' + volumes: + - ./docker:/docker + - ./magnumopus:/home/user/magnumopus + ports: + - 5000:5000 diff --git a/022-burette/magnum_opus_iii/docker/storage/storage.db b/022-burette/magnum_opus_iii/docker/storage/storage.db new file mode 100644 index 0000000..41e4173 Binary files /dev/null and b/022-burette/magnum_opus_iii/docker/storage/storage.db differ diff --git a/022-burette/magnum_opus_iii/gunicorn_config.py b/022-burette/magnum_opus_iii/gunicorn_config.py new file mode 100644 index 0000000..29db9d9 --- /dev/null +++ b/022-burette/magnum_opus_iii/gunicorn_config.py @@ -0,0 +1,5 @@ +port = '5000' +bind = "0.0.0.0:%s" % port +workers = 1 +timeout = 600 +reload = False diff --git a/022-burette/magnum_opus_iii/init_containers.sh b/022-burette/magnum_opus_iii/init_containers.sh new file mode 100755 index 0000000..0a64c94 --- /dev/null +++ b/022-burette/magnum_opus_iii/init_containers.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +mkdir -p docker/storage + +docker-compose run --user root web /init_entrypoint.sh +docker-compose run web python3 -m magnumopus.initialize diff --git a/022-burette/magnum_opus_iii/init_entrypoint.sh b/022-burette/magnum_opus_iii/init_entrypoint.sh new file mode 100755 index 0000000..8366386 --- /dev/null +++ b/022-burette/magnum_opus_iii/init_entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +chown -R user:user /docker/storage diff --git a/022-burette/magnum_opus_iii/magnumopus/__init__.py b/022-burette/magnum_opus_iii/magnumopus/__init__.py new file mode 100644 index 0000000..930f101 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/__init__.py @@ -0,0 +1,23 @@ +from quart_openapi import Pint + +def create_app(): + from . import models, resources, schemas, logger, repositories, injection, graph + + app = Pint(__name__, title='Magnum Opus') + + # This could be used to separate by environment + app.config.from_object('magnumopus.config.Config') + + # This helps avoid cyclic dependencies + modules = [] + + modules += logger.init_app(app) + modules += models.init_app(app) + modules += resources.init_app(app) + modules += repositories.init_app(app) + modules += schemas.init_app(app) + modules += graph.init_app(app) + + injection.init_app(app, modules) + + return app diff --git a/022-burette/magnum_opus_iii/magnumopus/config.py b/022-burette/magnum_opus_iii/magnumopus/config.py new file mode 100644 index 0000000..a9899f9 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/config.py @@ -0,0 +1,7 @@ +import os + +class Config: + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI', 'sqlite:///:memory:') + SQLALCHEMY_TRACK_MODIFICATIONS = False + + PANTRY_STORE = os.environ.get('MAGNUMOPUS_PANTRY_STORE', 'list') diff --git a/022-burette/magnum_opus_iii/magnumopus/graph.py b/022-burette/magnum_opus_iii/magnumopus/graph.py new file mode 100644 index 0000000..e4d0f90 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/graph.py @@ -0,0 +1,46 @@ +from quart import request, jsonify +from graphql import GraphQLSchema +from ariadne import ObjectType, make_executable_schema, graphql +from .schemas import init_graph as init_graph_schemas +from .resources import init_graph as init_graph_resources + +TYPE_DEFS = """ + type Query { + substances(nature: String!): [Substance] + } +""" + +class InjectorObjectType(ObjectType): + def __init__(self, *args, app=None, **kwargs): + super(InjectorObjectType, self).__init__(*args, **kwargs) + self._app = app + + def get_injector(self): + return self._app.extensions['injector'] + + def field(self, name: str): + g = super(InjectorObjectType, self).field(name) + def injected_resolver(f): + def _inject_resolver(*args, **kwargs): + self._app.logger.error(name) + inj = self.get_injector() + return inj.call_with_injection( + f, args=args, kwargs=kwargs + ) + return g(_inject_resolver) + return injected_resolver + +def init_app(app): + query = InjectorObjectType('Query', app=app) + + type_defs = [TYPE_DEFS] + init_graph_schemas(query) + resolvers = [query] + init_graph_resources(query) + + schema = make_executable_schema(type_defs, resolvers) + + return [ + lambda binder: binder.bind( + GraphQLSchema, + to=schema + ) + ] diff --git a/022-burette/magnum_opus_iii/magnumopus/index.py b/022-burette/magnum_opus_iii/magnumopus/index.py new file mode 100644 index 0000000..183c186 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/index.py @@ -0,0 +1,3 @@ +from . import create_app + +app = create_app() diff --git a/022-burette/magnum_opus_iii/magnumopus/initialize.py b/022-burette/magnum_opus_iii/magnumopus/initialize.py new file mode 100644 index 0000000..b251d32 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/initialize.py @@ -0,0 +1,9 @@ +from . import create_app +from .models import db + +if __name__ == "__main__": + # There are nicer ways around this, but this keeps it clear for an example + app = create_app() + + with app.app_context(): + db.create_all() diff --git a/022-burette/magnum_opus_iii/magnumopus/injection.py b/022-burette/magnum_opus_iii/magnumopus/injection.py new file mode 100644 index 0000000..00a8b45 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/injection.py @@ -0,0 +1,26 @@ +from injector import Injector +from quart.views import MethodViewType + +class ViewInjectorMeta(MethodViewType): + def get_injector(self): + return self.get_app().extensions['injector'] + + def __call__(cls, *args, **kwargs): + return cls.get_injector().create_object( + cls.__bases__[0], + additional_kwargs=kwargs + ) + +def init_app(app, modules): + modules.append(configure_injector) + + injctr = Injector() + for module in modules: + injctr.binder.install(module) + app.extensions['injector'] = injctr + +def configure_injector(binder): + """ + Add any general purpose injectables, not included in a submodule + """ + pass diff --git a/022-burette/magnum_opus_iii/magnumopus/logger.py b/022-burette/magnum_opus_iii/magnumopus/logger.py new file mode 100644 index 0000000..b5c4b4f --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/logger.py @@ -0,0 +1,6 @@ +import logging + +def init_app(app): + app.logger.addHandler(logging.StreamHandler()) + app.logger.setLevel(logging.INFO) + return [] diff --git a/022-burette/magnum_opus_iii/magnumopus/models/__init__.py b/022-burette/magnum_opus_iii/magnumopus/models/__init__.py new file mode 100644 index 0000000..de02858 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/models/__init__.py @@ -0,0 +1,11 @@ +from .base import db +from flask_sqlalchemy import SQLAlchemy + +def init_app(app): + # db.init_app(app) + return [configure_injector] + +def configure_injector(binding): + binding.bind( + SQLAlchemy, to=db + ) diff --git a/022-burette/magnum_opus_iii/magnumopus/models/base.py b/022-burette/magnum_opus_iii/magnumopus/models/base.py new file mode 100644 index 0000000..f0b13d6 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/models/base.py @@ -0,0 +1,3 @@ +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() diff --git a/022-burette/magnum_opus_iii/magnumopus/models/substance.py b/022-burette/magnum_opus_iii/magnumopus/models/substance.py new file mode 100644 index 0000000..ba91c35 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/models/substance.py @@ -0,0 +1,40 @@ +from . import db +from sqlalchemy_utils import ScalarListType + +class SubstanceMustBeFreshToProcessException(Exception): + pass + +class Substance(db.Model): + __tablename__ = 'substances' + + id = db.Column(db.Integer, primary_key=True) + nature = db.Column(db.String(32), default='Unknown') + state = db.Column(ScalarListType()) + + def __init__(self, nature='Unknown'): + self.state = [] + self.nature = nature + + super(Substance, self).__init__() + + def _process(self, process_name): + # Example of leakage of persistence behaviour into + # domain, due to db.Model -- we must copy the state list to + # ensure it is seen to change... + state = self.state[:] + state.append(process_name) + self.state = state + + return self + + def cook(self): + return self._process('cooked') + + def pickle(self): + return self._process('pickled') + + def ferment(self): + return self._process('fermented') + + def wash(self): + return self._process('washed') diff --git a/022-burette/magnum_opus_iii/magnumopus/repositories/__init__.py b/022-burette/magnum_opus_iii/magnumopus/repositories/__init__.py new file mode 100644 index 0000000..6135fe4 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/repositories/__init__.py @@ -0,0 +1,18 @@ +from .pantry import Pantry +from .list_pantry import ListPantry +from .sqlalchemy_pantry import SQLAlchemyPantry + +PANTRY_STORES = { + 'sqlalchemy': SQLAlchemyPantry, + 'list': ListPantry() # we instantiate this, as we want a singleton cupboard +} + +def init_app(app): + return [lambda binder: configure_injector(binder, app)] + +def configure_injector(binder, app): + pantry_cls = PANTRY_STORES[app.config['PANTRY_STORE']] + + binder.bind( + Pantry, to=pantry_cls + ) diff --git a/022-burette/magnum_opus_iii/magnumopus/repositories/list_pantry.py b/022-burette/magnum_opus_iii/magnumopus/repositories/list_pantry.py new file mode 100644 index 0000000..9d6dbe4 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/repositories/list_pantry.py @@ -0,0 +1,26 @@ +class ListPantry: + def __init__(self): + self._cupboard = [] + + def empty_pantry(self): + self._cupboard = [] + + def add_substance(self, substance): + self._cupboard.append(substance) + + def find_substances_by_nature(self, nature): + return [substance for substance in self._cupboard if substance.nature == nature] + + def count_all_substances(self): + return len(self._cupboard) + + def commit(self): + # Give each substance an ID, if it does not have one + free_ids = iter( + set(range(1, len(self._cupboard) + 1)) - + set([substance.id for substance in self._cupboard if substance]) + ) + + for substance in self._cupboard: + if not substance.id: + substance.id = next(free_ids) diff --git a/022-burette/magnum_opus_iii/magnumopus/repositories/pantry.py b/022-burette/magnum_opus_iii/magnumopus/repositories/pantry.py new file mode 100644 index 0000000..3a342a5 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/repositories/pantry.py @@ -0,0 +1,25 @@ +from abc import ABC, abstractmethod + +class Pantry(ABC): + def __init__(self): + pass + + @abstractmethod + def do_empty(self): + pass + + @abstractmethod + def add_substance(self, substance): + pass + + @abstractmethod + def find_substances_by_nature(self, nature): + pass + + @abstractmethod + def count_all_substances(self): + pass + + @abstractmethod + def commit(self): + pass diff --git a/022-burette/magnum_opus_iii/magnumopus/repositories/sqlalchemy_pantry.py b/022-burette/magnum_opus_iii/magnumopus/repositories/sqlalchemy_pantry.py new file mode 100644 index 0000000..d9135f0 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/repositories/sqlalchemy_pantry.py @@ -0,0 +1,31 @@ +from flask_sqlalchemy import SQLAlchemy +from injector import inject + +from ..models.substance import Substance +from ..models import db + +class SQLAlchemyPantry: + @inject + def __init__(self, db: SQLAlchemy): + self._db = db + + def empty_pantry(self): + Substance.query.delete() + + # A more involved solution would open and close the pantry... like + # a cupboard door, or a Unit of Work + + # Note how we're committing too frequently? + def add_substance(self, substance): + self._db.session.add(substance) + return substance + + def find_substances_by_nature(self, nature): + substances = Substance.query.filter_by(nature=nature).all() + return substances + + def count_all_substances(self): + return Substance.query.count() + + def commit(self): + self._db.session.commit() diff --git a/022-burette/magnum_opus_iii/magnumopus/resources/__init__.py b/022-burette/magnum_opus_iii/magnumopus/resources/__init__.py new file mode 100644 index 0000000..cbe6bf9 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/resources/__init__.py @@ -0,0 +1,14 @@ +from . import substance +from . import alembic_instruction +from . import graph + +def init_app(app): + substance.init_app(app) + alembic_instruction.init_app(app) + graph.init_app(app) + return [] + +def init_graph(graph): + resolvers = [] + resolvers += substance.init_graph(graph) + return resolvers diff --git a/022-burette/magnum_opus_iii/magnumopus/resources/alembic_instruction.py b/022-burette/magnum_opus_iii/magnumopus/resources/alembic_instruction.py new file mode 100644 index 0000000..a6ff22c --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/resources/alembic_instruction.py @@ -0,0 +1,57 @@ +from quart import request +from quart_openapi import Resource +from injector import inject +from ..injection import ViewInjectorMeta +from ..repositories.pantry import Pantry +from ..models.substance import Substance +from ..schemas.substance_schema import SubstanceSchema +from ..services.alembic_instruction_handler import AlembicInstructionHandler, AlembicInstruction + +class AlembicInstructionResource(Resource): + @inject + def __init__(self, pantry: Pantry, substance_schema: SubstanceSchema): + super(AlembicInstructionResource, self).__init__() + + self._pantry = pantry + self._substance_schema = substance_schema + + async def get(self): + """This should return past requests/commands.""" + pass + + async def post(self): + """ + Add an instruction for the alembic. + + Note that POST is _not_ assumed to be idempotent, unlike PUT + """ + + args = await request.get_json() + + instruction_type = args['instruction_type'] + + pantry = self._pantry + + instruction_handler = AlembicInstructionHandler() + + # This could do with deserialization... + instruction = AlembicInstruction( + instruction_type=args['instruction_type'], + natures=args['natures'].split(','), + action=args['action'] if 'action' in args else '' + ) + + result = instruction_handler.handle(instruction, pantry) + + pantry.add_substance(result) + + pantry.commit() + + return self._substance_schema.dump(result), 201 + + +def init_app(app): + class AppAlembicInstructionResource(AlembicInstructionResource, metaclass=ViewInjectorMeta): + get_app = lambda: app + + app.route('/alembic_instruction', endpoint='alembic_instruction')(AppAlembicInstructionResource) diff --git a/022-burette/magnum_opus_iii/magnumopus/resources/graph.py b/022-burette/magnum_opus_iii/magnumopus/resources/graph.py new file mode 100644 index 0000000..7a44b5c --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/resources/graph.py @@ -0,0 +1,39 @@ +from quart import request, jsonify +from quart_openapi import Resource +from injector import inject +from typing import Dict +from ariadne import graphql +from ariadne.constants import PLAYGROUND_HTML +from graphql.type import GraphQLSchema +from ..injection import ViewInjectorMeta +from ..repositories.pantry import Pantry +from ..models import db + +class GraphResource(Resource): + @inject + def __init__(self, schema: GraphQLSchema): + super(GraphResource, self).__init__() + + self._schema = schema + + async def get(self): + return (PLAYGROUND_HTML, 200) + + async def post(self): + data = await request.get_json() + success, result = await graphql( + self._schema, + data, + context_value=request + ) + + return jsonify(result), (200 if success else 400) + + +def init_app(app): + class AppGraphResource(GraphResource, metaclass=ViewInjectorMeta): + get_app = lambda: app + + app.route('/graphql', endpoint='graphql')(AppGraphResource) + + return [] diff --git a/022-burette/magnum_opus_iii/magnumopus/resources/substance.py b/022-burette/magnum_opus_iii/magnumopus/resources/substance.py new file mode 100644 index 0000000..2052a7b --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/resources/substance.py @@ -0,0 +1,69 @@ +from quart import request +from quart_openapi import Resource +from injector import inject +from typing import Dict +from ariadne import ObjectType +from ..injection import ViewInjectorMeta +from ..repositories.pantry import Pantry +from ..models import db +from ..models.substance import Substance +from ..schemas.substance_schema import SubstanceSchema + +class SubstanceResource(Resource): + @inject + def __init__(self, pantry: Pantry, substance_schemas: Dict[str, SubstanceSchema]): + super(SubstanceResource, self).__init__() + + self._pantry = pantry + self._substance_schema = substance_schemas['one'] + self._substances_schema = substance_schemas['many'] + + async def get(self): + nature = request.args.get('nature') + + substances = self._pantry.find_substances_by_nature(nature) + + return { + 'result': self._substances_schema.dump(substances) + } + + async def post(self): + args = await request.get_json() + + nature = args['nature'] + + pantry = self._pantry + + substance = Substance(nature=nature) + + pantry.add_substance(substance) + + pantry.commit() + + return self._substance_schema.dump(substance), 201 + + +def init_app(app): + class AppSubstanceResource(SubstanceResource, metaclass=ViewInjectorMeta): + get_app = lambda: app + + app.route('/substance', endpoint='SubstanceResource')(AppSubstanceResource) + +def init_graph(query): + substance = ObjectType('Substance') + + @query.field('substances') + @inject + def resolve_substances(obj, info, pantry: Pantry, *_, nature='Unknown'): + substances = pantry.find_substances_by_nature(nature) + return substances + + @substance.field('nature') + def resolve_nature(obj, *_): + return obj.nature + + @substance.field('state') + def resolve_state(obj, *_): + return obj.state + + return [substance] diff --git a/022-burette/magnum_opus_iii/magnumopus/schemas/__init__.py b/022-burette/magnum_opus_iii/magnumopus/schemas/__init__.py new file mode 100644 index 0000000..58b0ef1 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/schemas/__init__.py @@ -0,0 +1,29 @@ +from typing import Dict +from flask_marshmallow import Marshmallow + +ma = Marshmallow() + +def init_app(app): + ma.init_app(app) + return [configure_injector] + +def configure_injector(binder): + from .substance_schema import SubstanceSchema + + binder.bind( + SubstanceSchema, to=SubstanceSchema() + ) + + binder.multibind( + Dict[str, SubstanceSchema], to={ + 'one': SubstanceSchema(), + 'many': SubstanceSchema(many=True) + } + ) + +def init_graph(query): + from .substance_schema import init_graph as init_graph_substance + + return [ + init_graph_substance(query) + ] diff --git a/022-burette/magnum_opus_iii/magnumopus/schemas/substance_schema.py b/022-burette/magnum_opus_iii/magnumopus/schemas/substance_schema.py new file mode 100644 index 0000000..7c99105 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/schemas/substance_schema.py @@ -0,0 +1,29 @@ +from marshmallow import fields + +from . import ma + +from ..models.substance import Substance +from ..services.assessor import assess_whether_substance_is_philosophers_stone + +SUBSTANCE_GRAPH_SCHEMA = """ + type Substance { + nature: String!, + state: [String]! + } +""" + +class SubstanceSchema(ma.SQLAlchemySchema): + is_philosophers_stone = fields.Function( + assess_whether_substance_is_philosophers_stone + ) + + class Meta: + model = Substance + fields = ('id', 'nature', 'is_philosophers_stone', 'state') + + id = fields.Integer() + nature = fields.String() + state = fields.Function(lambda model: model.state or []) + +def init_graph(query): + return SUBSTANCE_GRAPH_SCHEMA diff --git a/022-burette/magnum_opus_iii/magnumopus/services/__init__.py b/022-burette/magnum_opus_iii/magnumopus/services/__init__.py new file mode 100644 index 0000000..561fd25 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/services/__init__.py @@ -0,0 +1,9 @@ +from .alembic import Alembic + +def init_app(app): + return [configure_injector] + +def configure_injector(binder): + binder.bind( + Alembic, to=Alembic + ) diff --git a/022-burette/magnum_opus_iii/magnumopus/services/alembic.py b/022-burette/magnum_opus_iii/magnumopus/services/alembic.py new file mode 100644 index 0000000..5fc05b2 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/services/alembic.py @@ -0,0 +1,51 @@ +from ..models.substance import Substance + +class NotEnoughSubstancesToMixException(Exception): + pass + +class UnknownProcessException(Exception): + pass + + +MIXTURES = { + ('Mercury', 'Salt', 'Sulphur'): 'Gloop' +} + + +class Alembic: + _nature_of_unknown_mixture = 'Sludge' + + @staticmethod + def _produce(nature): + return Substance(nature=nature) + + def mix(self, *substances): + if len(substances) < 2: + raise NotEnoughSubstancesToMixException() + + constituents = [substance.nature for substance in substances] + + # This gives us a canonical, ordered way of expressing our + # constituents that we can use as a recipe look-up + ingredient_list = tuple(sorted(constituents)) + + try: + nature = MIXTURES[ingredient_list] + except KeyError: + nature = self._nature_of_unknown_mixture + + return self._produce(nature) + + def process(self, process_name, substance): + if process_name == 'ferment': + result = substance.ferment() + elif process_name == 'cook': + result = substance.cook() + elif process_name == 'wash': + result = substance.wash() + elif process_name == 'pickle': + result = substance.pickle() + else: + raise UnknownProcessException() + + return result diff --git a/022-burette/magnum_opus_iii/magnumopus/services/alembic_instruction_handler.py b/022-burette/magnum_opus_iii/magnumopus/services/alembic_instruction_handler.py new file mode 100644 index 0000000..54fbb40 --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/services/alembic_instruction_handler.py @@ -0,0 +1,36 @@ +from dataclasses import dataclass +from injector import inject + +from .alembic import Alembic +from ..repositories.pantry import Pantry + +class UnknownAlembicInstructionException(Exception): + pass + +@dataclass +class AlembicInstruction: + instruction_type: str + natures: list + action: str = '' + +class AlembicInstructionHandler: + @inject + def handle(self, instruction: AlembicInstruction, pantry: Pantry): + natures = instruction.natures + action = instruction.action + instruction_type = instruction.instruction_type + + # Clearly need some validation here! + substances = [pantry.find_substances_by_nature(nature)[0] for nature in natures] + + alembic = Alembic() + + if instruction_type == 'mix': + result = alembic.mix(*substances) + elif instruction_type == 'process': + result = alembic.process(action, substances[0]) + else: + raise UnknownAlembicInstructionException(f'Unknown instruction: {action}') + + print(result.state, result.id, 'x') + return result diff --git a/022-burette/magnum_opus_iii/magnumopus/services/assessor.py b/022-burette/magnum_opus_iii/magnumopus/services/assessor.py new file mode 100644 index 0000000..94d564d --- /dev/null +++ b/022-burette/magnum_opus_iii/magnumopus/services/assessor.py @@ -0,0 +1,2 @@ +def assess_whether_substance_is_philosophers_stone(substance): + return substance.nature == 'Gloop' and substance.state == ['cooked', 'washed', 'pickled', 'fermented'] diff --git a/022-burette/magnum_opus_iii/pytestdebug.log b/022-burette/magnum_opus_iii/pytestdebug.log new file mode 100644 index 0000000..836541b --- /dev/null +++ b/022-burette/magnum_opus_iii/pytestdebug.log @@ -0,0 +1,4688 @@ +versions pytest-5.4.3, py-1.9.0, python-3.8.2.final.0 +cwd=/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii +args=('--debug',) + + pytest_cmdline_main [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_configure [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.LFPlugin object at 0x7f780666a820> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.NFPlugin object at 0x7f780666a9a0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + early skip of rewriting module: faulthandler [assertion] + pytest_configure [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_configure --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.faulthandler.FaultHandlerHooks object at 0x7f780666aa60> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.stepwise.StepwisePlugin object at 0x7f780666ab80> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + early skip of rewriting module: pdb [assertion] + early skip of rewriting module: cmd [assertion] + pytest_plugin_registered [hook] + plugin: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.config.Config object at 0x7f78089fd5b0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: > err=> in_=> _state='suspended' _in_suspended=False> _capture_fixture=None> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: testsfailed=0 testscollected=0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.LFPlugin object at 0x7f780666a820> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.NFPlugin object at 0x7f780666a9a0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.faulthandler.FaultHandlerHooks object at 0x7f780666aa60> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.stepwise.StepwisePlugin object at 0x7f780666ab80> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.terminal.TerminalReporter object at 0x7f780666aee0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.logging.LoggingPlugin object at 0x7f7806694820> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + finish pytest_configure --> [] [hook] + pytest_sessionstart [hook] + session: testsfailed=0 testscollected=0> + pytest_plugin_registered [hook] + plugin: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.config.Config object at 0x7f78089fd5b0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: > err=> in_=> _state='suspended' _in_suspended=False> _capture_fixture=None> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: testsfailed=0 testscollected=0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.LFPlugin object at 0x7f780666a820> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.cacheprovider.NFPlugin object at 0x7f780666a9a0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.faulthandler.FaultHandlerHooks object at 0x7f780666aa60> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.stepwise.StepwisePlugin object at 0x7f780666ab80> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.terminal.TerminalReporter object at 0x7f780666aee0> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.logging.LoggingPlugin object at 0x7f7806694820> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_plugin_registered [hook] + plugin: <_pytest.fixtures.FixtureManager object at 0x7f7806694a60> + manager: <_pytest.config.PytestPluginManager object at 0x7f78091f69d0> + finish pytest_plugin_registered --> [] [hook] + pytest_report_header [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + startdir: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii + finish pytest_report_header --> [['rootdir: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii', 'plugins: pep8-1.0.6, asyncio-0.14.0, cov-2.10.0'], ['using: pytest-5.4.3 pylib-1.9.0', 'setuptools registered plugins:', ' pytest-pep8-1.0.6 at /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.env/lib/python3.8/site-packages/pytest_pep8.py', ' pytest-asyncio-0.14.0 at /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.env/lib/python3.8/site-packages/pytest_asyncio/plugin.py', ' pytest-cov-2.10.0 at /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.env/lib/python3.8/site-packages/pytest_cov/plugin.py']] [hook] + finish pytest_sessionstart --> [] [hook] + pytest_collection [hook] + session: testsfailed=0 testscollected=0> + perform_collect testsfailed=0 testscollected=0> ['/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii'] [collection] + pytest_collectstart [hook] + collector: testsfailed=0 testscollected=0> + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: testsfailed=0 testscollected=0> + processing argument (local('/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii'), []) [collection] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + early skip of rewriting module: py._code [assertion] + early skip of rewriting module: py._code.code [assertion] + early skip of rewriting module: repr [assertion] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.pytest_cache + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.env + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> True [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.tox + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.coverage + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.coverage + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.gitignore + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/.gitignore + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/Dockerfile + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/Dockerfile + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/MANIFEST.in + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/MANIFEST.in + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/README.md + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/README.md + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/RULES.md + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/RULES.md + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker-compose.yml + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker-compose.yml + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/gunicorn_config.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/gunicorn_config.py + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/init_containers.sh + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/init_containers.sh + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/init_entrypoint.sh + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/init_entrypoint.sh + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/pytestdebug.log + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/pytestdebug.log + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/requirements.txt + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/requirements.txt + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/setup.cfg + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/setup.cfg + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/setup.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/setup.py + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tox.ini + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tox.ini + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/PKG-INFO + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/PKG-INFO + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/SOURCES.txt + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/SOURCES.txt + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/dependency_links.txt + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/dependency_links.txt + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/requires.txt + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/requires.txt + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/top_level.txt + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/aiomagnumopus.egg-info/top_level.txt + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker/storage + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker/storage + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker/storage/storage.db + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/docker/storage/storage.db + parent: testsfailed=0 testscollected=0> + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain + parent: testsfailed=0 testscollected=0> + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__init__.py + parent: testsfailed=0 testscollected=0> + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__init__.py + parent: testsfailed=0 testscollected=0> + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/Pipfile + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/Pipfile + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/config.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/config.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/index.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/index.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/initialize.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/initialize.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/injection.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/injection.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/logger.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/logger.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/base.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/base.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/substance.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/models/substance.py + parent: + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/list_pantry.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/list_pantry.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/pantry.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/pantry.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/sqlalchemy_pantry.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/repositories/sqlalchemy_pantry.py + parent: + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/alembic_instruction.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/alembic_instruction.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/substance.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/resources/substance.py + parent: + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/substance_schema.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/schemas/substance_schema.py + parent: + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/alembic.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/alembic.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/alembic_instruction_handler.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/alembic_instruction_handler.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/assessor.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/magnumopus/services/assessor.py + parent: + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_directory [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain + parent: + finish pytest_collect_directory --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/Pipfile + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/Pipfile + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/conftest.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/conftest.py + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__init__.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + finish pytest_make_collect_report --> [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/.coverage + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/.coverage + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/Pipfile + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/Pipfile + parent: + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + early skip of rewriting module: tests.application [assertion] + find_module called for: tests.application.test_alembic_instruction_resource [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py [assertion] + find_module called for: tests.application.test_substance_resource [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.application.test_alembic_instruction_resource + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.application + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.application.test_alembic_instruction_resource', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_alembic_instruction_resource.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__pycache__/test_alembic_instruction_resource.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_app + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: is_dictionary_inside + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_substance_request + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_alembic_instruction_request + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_create_alembic_mix_instruction + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f78065e04c0> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_create_alembic_process_instruction + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806649640> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + find_module called for: tests.application.test_philosophers_stone [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.application.test_philosophers_stone + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.application + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.application.test_philosophers_stone', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_philosophers_stone.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__pycache__/test_philosophers_stone.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_app + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: is_dictionary_inside + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_create_philosophers_stone + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f78065e0fa0> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.application.test_substance_resource + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.application + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.application.test_substance_resource', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/test_substance_resource.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/application/__pycache__/test_substance_resource.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_app + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: is_dictionary_inside + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: create_substance_request + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: index_substances_request + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_create_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f78065e04c0> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_get_substances + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f78065e0550> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + pytest_ignore_collect [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_ignore_collect --> None [hook] + pytest_collect_file [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py + parent: + pytest_pycollect_makemodule [hook] + path: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py + parent: + finish pytest_pycollect_makemodule --> [hook] + finish pytest_collect_file --> [] [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + early skip of rewriting module: tests.domain [assertion] + find_module called for: tests.domain.test_alembic [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py [assertion] + early skip of rewriting module: magnumopus.services [assertion] + early skip of rewriting module: magnumopus.services.alembic [assertion] + early skip of rewriting module: magnumopus.models.substance [assertion] + early skip of rewriting module: sqlalchemy_utils [assertion] + early skip of rewriting module: sqlalchemy_utils.aggregates [assertion] + early skip of rewriting module: sqlalchemy_utils.functions [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.database [assertion] + early skip of rewriting module: sqlalchemy_utils.utils [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.orm [assertion] + early skip of rewriting module: sqlalchemy.ext.hybrid [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.foreign_keys [assertion] + early skip of rewriting module: sqlalchemy_utils.query_chain [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.mock [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.render [assertion] + early skip of rewriting module: sqlalchemy_utils.functions.sort_query [assertion] + early skip of rewriting module: sqlalchemy_utils.relationships [assertion] + early skip of rewriting module: sqlalchemy_utils.relationships.chained_join [assertion] + early skip of rewriting module: sqlalchemy_utils.asserts [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.base [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.array [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.hstore [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.json [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.ranges [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.pg8000 [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.psycopg2 [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.psycopg2cffi [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.pygresql [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.pypostgresql [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.zxjdbc [assertion] + early skip of rewriting module: sqlalchemy.connectors [assertion] + early skip of rewriting module: sqlalchemy.connectors.zxJDBC [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.dml [assertion] + early skip of rewriting module: sqlalchemy.dialects.postgresql.ext [assertion] + early skip of rewriting module: sqlalchemy_utils.exceptions [assertion] + early skip of rewriting module: sqlalchemy_utils.expressions [assertion] + early skip of rewriting module: sqlalchemy.ext.compiler [assertion] + early skip of rewriting module: sqlalchemy_utils.generic [assertion] + early skip of rewriting module: sqlalchemy_utils.i18n [assertion] + early skip of rewriting module: babel [assertion] + early skip of rewriting module: sqlalchemy_utils.listeners [assertion] + early skip of rewriting module: sqlalchemy_utils.models [assertion] + early skip of rewriting module: sqlalchemy_utils.observer [assertion] + early skip of rewriting module: sqlalchemy_utils.path [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives.country [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives.currency [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives.ltree [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives.weekday [assertion] + early skip of rewriting module: sqlalchemy_utils.primitives.weekdays [assertion] + early skip of rewriting module: sqlalchemy_utils.proxy_dict [assertion] + early skip of rewriting module: sqlalchemy_utils.types [assertion] + early skip of rewriting module: sqlalchemy_utils.types.arrow [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime.arrow_datetime [assertion] + early skip of rewriting module: arrow [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime.pendulum_date [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime.pendulum_datetime [assertion] + early skip of rewriting module: pendulum [assertion] + early skip of rewriting module: pendulum [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime.enriched_datetime_type [assertion] + early skip of rewriting module: sqlalchemy_utils.types.scalar_coercible [assertion] + early skip of rewriting module: arrow [assertion] + early skip of rewriting module: sqlalchemy_utils.types.choice [assertion] + early skip of rewriting module: sqlalchemy_utils.types.color [assertion] + early skip of rewriting module: colour [assertion] + early skip of rewriting module: sqlalchemy_utils.types.country [assertion] + early skip of rewriting module: sqlalchemy_utils.types.currency [assertion] + early skip of rewriting module: sqlalchemy_utils.types.email [assertion] + early skip of rewriting module: sqlalchemy_utils.operators [assertion] + early skip of rewriting module: sqlalchemy_utils.types.encrypted [assertion] + early skip of rewriting module: sqlalchemy_utils.types.encrypted.encrypted_type [assertion] + early skip of rewriting module: sqlalchemy_utils.types.encrypted.padding [assertion] + early skip of rewriting module: sqlalchemy_utils.types.json [assertion] + early skip of rewriting module: anyjson [assertion] + early skip of rewriting module: cryptography [assertion] + early skip of rewriting module: dateutil [assertion] + early skip of rewriting module: sqlalchemy_utils.types.enriched_datetime.enriched_date_type [assertion] + early skip of rewriting module: sqlalchemy_utils.types.ip_address [assertion] + early skip of rewriting module: ipaddress [assertion] + early skip of rewriting module: sqlalchemy_utils.types.locale [assertion] + early skip of rewriting module: babel [assertion] + early skip of rewriting module: sqlalchemy_utils.types.ltree [assertion] + early skip of rewriting module: sqlalchemy_utils.types.password [assertion] + early skip of rewriting module: sqlalchemy.dialects.oracle [assertion] + early skip of rewriting module: sqlalchemy.dialects.oracle.base [assertion] + early skip of rewriting module: sqlalchemy.dialects.oracle.cx_oracle [assertion] + early skip of rewriting module: sqlalchemy.dialects.oracle.zxjdbc [assertion] + early skip of rewriting module: sqlalchemy.dialects.sqlite [assertion] + early skip of rewriting module: sqlalchemy.dialects.sqlite.base [assertion] + early skip of rewriting module: sqlalchemy.dialects.sqlite.json [assertion] + early skip of rewriting module: sqlalchemy.dialects.sqlite.pysqlcipher [assertion] + early skip of rewriting module: sqlalchemy.dialects.sqlite.pysqlite [assertion] + early skip of rewriting module: sqlalchemy.ext.mutable [assertion] + early skip of rewriting module: passlib [assertion] + early skip of rewriting module: sqlalchemy_utils.types.pg_composite [assertion] + early skip of rewriting module: psycopg2 [assertion] + early skip of rewriting module: sqlalchemy_utils.types.phone_number [assertion] + early skip of rewriting module: phonenumbers [assertion] + early skip of rewriting module: sqlalchemy_utils.types.range [assertion] + early skip of rewriting module: intervals [assertion] + early skip of rewriting module: sqlalchemy_utils.types.scalar_list [assertion] + early skip of rewriting module: sqlalchemy_utils.types.timezone [assertion] + early skip of rewriting module: sqlalchemy_utils.types.ts_vector [assertion] + early skip of rewriting module: sqlalchemy_utils.types.url [assertion] + early skip of rewriting module: furl [assertion] + early skip of rewriting module: sqlalchemy_utils.types.uuid [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.adodbapi [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.base [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.information_schema [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.mxodbc [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.pyodbc [assertion] + early skip of rewriting module: sqlalchemy.connectors.pyodbc [assertion] + early skip of rewriting module: sqlalchemy.connectors.mxodbc [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.pymssql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mssql.zxjdbc [assertion] + early skip of rewriting module: sqlalchemy_utils.types.weekdays [assertion] + early skip of rewriting module: sqlalchemy_utils.types.bit [assertion] + early skip of rewriting module: sqlalchemy_utils.view [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.domain.test_alembic + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.domain + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.domain.test_alembic', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__pycache__/test_alembic.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: Alembic + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: NotEnoughSubstancesToMixException + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: UnknownProcessException + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: Substance + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_set_up_my_alembic + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_mix_multiple_substances_in_my_alembic + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_cannot_mix_one_substance_in_my_alembic + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_mixing_sulphur_salt_and_mercury_gives_gloop + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_mixing_other_recipes_gives_sludge + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_process_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_cannot_perform_unknown_process + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806623d30> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + find_module called for: tests.domain.test_alembic_instruction_handler [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py [assertion] + early skip of rewriting module: magnumopus.services.alembic_instruction_handler [assertion] + early skip of rewriting module: injector [assertion] + early skip of rewriting module: magnumopus.repositories [assertion] + early skip of rewriting module: magnumopus.repositories.pantry [assertion] + early skip of rewriting module: magnumopus.repositories.list_pantry [assertion] + early skip of rewriting module: magnumopus.repositories.sqlalchemy_pantry [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.domain.test_alembic_instruction_handler + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.domain + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.domain.test_alembic_instruction_handler', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_alembic_instruction_handler.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__pycache__/test_alembic_instruction_handler.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: AlembicInstruction + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: AlembicInstructionHandler + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: ListPantry + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: Substance + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: instruction_unknown + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: instruction + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pantry + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_set_up_my_alembic_instruction_handler + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325040> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + find_module called for: tests.domain.test_pantry [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.domain.test_pantry + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.domain + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.domain.test_pantry', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_pantry.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__pycache__/test_pantry.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pytest + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: ListPantry + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: Substance + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: list_pantry + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: pantries + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_add_to_pantry + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f78063257f0> + pytest_make_parametrize_id [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + val: list + argname: pantry_type + finish pytest_make_parametrize_id --> None [hook] + early skip of rewriting module: encodings.unicode_escape [assertion] + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_retrieve_substance_from_pantry_by_nature + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325670> + pytest_make_parametrize_id [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + val: list + argname: pantry_type + finish pytest_make_parametrize_id --> None [hook] + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + genitems [collection] + pytest_collectstart [hook] + collector: + finish pytest_collectstart --> [] [hook] + pytest_make_collect_report [hook] + collector: + find_module called for: tests.domain.test_substance [assertion] + matched test file '/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py' [assertion] + found cached rewritten pyc for /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py [assertion] + pytest_pycollect_makeitem [hook] + collector: + name: __name__ + obj: tests.domain.test_substance + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __doc__ + obj: None + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __package__ + obj: tests.domain + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __loader__ + obj: <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370> + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __spec__ + obj: ModuleSpec(name='tests.domain.test_substance', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f7808885370>, origin='/home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py') + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __file__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/test_substance.py + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __cached__ + obj: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii/tests/domain/__pycache__/test_substance.cpython-38.pyc + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __builtins__ + obj: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'MemoryError': , 'BufferError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-D (i.e. EOF) to exit, 'exit': Use exit() or Ctrl-D (i.e. EOF) to exit, 'copyright': Copyright (c) 2001-2020 Python Software Foundation. +All Rights Reserved. + +Copyright (c) 2000 BeOpen.com. +All Rights Reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All Rights Reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. +All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information., 'license': Type license() to see the full license text, 'help': Type help() for interactive help, or help(object) for help about object.} + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @py_builtins + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: @pytest_ar + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: Substance + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_cook_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_wash_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_pickle_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_ferment_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_can_cook_and_ferment_substance + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: test_the_order_of_processes_applied_to_a_substance_matters + obj: + pytest_generate_tests [hook] + metafunc: <_pytest.python.Metafunc object at 0x7f7806325e20> + finish pytest_generate_tests --> [] [hook] + finish pytest_pycollect_makeitem --> [] [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __repr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __getattribute__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __setattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __delattr__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __new__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dir__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __dict__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __hash__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __str__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __lt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __le__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __eq__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ne__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __gt__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __ge__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce_ex__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __reduce__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __subclasshook__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __init_subclass__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __format__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __sizeof__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + pytest_pycollect_makeitem [hook] + collector: + name: __class__ + obj: + finish pytest_pycollect_makeitem --> None [hook] + finish pytest_make_collect_report --> [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + genitems [collection] + pytest_itemcollected [hook] + item: + finish pytest_itemcollected --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + pytest_collectreport [hook] + report: + finish pytest_collectreport --> [] [hook] + pytest_collection_modifyitems [hook] + session: testsfailed=0 testscollected=0> + config: <_pytest.config.Config object at 0x7f78089fd5b0> + items: [, , , , , , , , , , , , , , , , , , , , ] + finish pytest_collection_modifyitems --> [] [hook] + pytest_collection_finish [hook] + session: testsfailed=0 testscollected=0> + pytest_report_collectionfinish [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + startdir: /home/philtweir/Work/Training/PythonCourse/python-course/022-burette/magnum_opus_ii + items: [, , , , , , , , , , , , , , , , , , , , ] + finish pytest_report_collectionfinish --> [] [hook] + finish pytest_collection_finish --> [] [hook] + finish pytest_collection --> [, , , , , , , , , , , , , , , , , , , , ] [hook] + pytest_runtestloop [hook] + session: testsfailed=0 testscollected=21> + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/application/test_alembic_instruction_resource.py::test_create_alembic_mix_instruction + location: ('tests/application/test_alembic_instruction_resource.py', 16, 'test_create_alembic_mix_instruction') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> <_UnixSelectorEventLoop running=False closed=False debug=False> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + early skip of rewriting module: magnumopus.resources [assertion] + early skip of rewriting module: magnumopus.resources.substance [assertion] + early skip of rewriting module: magnumopus.injection [assertion] + early skip of rewriting module: magnumopus.schemas [assertion] + early skip of rewriting module: flask_marshmallow [assertion] + early skip of rewriting module: distutils [assertion] + early skip of rewriting module: distutils.version [assertion] + early skip of rewriting module: marshmallow [assertion] + early skip of rewriting module: marshmallow.schema [assertion] + early skip of rewriting module: marshmallow.base [assertion] + early skip of rewriting module: marshmallow.fields [assertion] + early skip of rewriting module: marshmallow.validate [assertion] + early skip of rewriting module: marshmallow.types [assertion] + early skip of rewriting module: marshmallow.exceptions [assertion] + early skip of rewriting module: marshmallow.utils [assertion] + early skip of rewriting module: marshmallow.class_registry [assertion] + early skip of rewriting module: marshmallow.error_store [assertion] + early skip of rewriting module: marshmallow.orderedset [assertion] + early skip of rewriting module: marshmallow.decorators [assertion] + early skip of rewriting module: flask_marshmallow.fields [assertion] + early skip of rewriting module: flask_marshmallow.schema [assertion] + early skip of rewriting module: flask_marshmallow.compat [assertion] + early skip of rewriting module: flask_marshmallow.sqla [assertion] + early skip of rewriting module: six.moves.urllib [assertion] + early skip of rewriting module: marshmallow_sqlalchemy [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema.model_schema [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.convert [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.base [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.reflection [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.enumerated [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.types [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.json [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.cymysql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.mysqldb [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.gaerdbms [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.mysqlconnector [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.oursql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.pymysql [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.pyodbc [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.zxjdbc [assertion] + early skip of rewriting module: sqlalchemy.dialects.mysql.dml [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.exceptions [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.fields [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema.schema_meta [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema.load_instance_mixin [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema.table_schema [assertion] + early skip of rewriting module: marshmallow_sqlalchemy.schema.sqlalchemy_schema [assertion] + early skip of rewriting module: magnumopus.schemas.substance_schema [assertion] + early skip of rewriting module: magnumopus.services.assessor [assertion] + early skip of rewriting module: magnumopus.resources.alembic_instruction [assertion] + early skip of rewriting module: magnumopus.logger [assertion] + early skip of rewriting module: magnumopus.config [assertion] + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + pytest_assertrepr_compare [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + op: == + left: 500 + right: 201 + finish pytest_assertrepr_compare --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: > + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_exception_interact [hook] + node: + call: > + report: + finish pytest_exception_interact --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/application/test_alembic_instruction_resource.py::test_create_alembic_mix_instruction + location: ('tests/application/test_alembic_instruction_resource.py', 16, 'test_create_alembic_mix_instruction') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/application/test_alembic_instruction_resource.py::test_create_alembic_process_instruction + location: ('tests/application/test_alembic_instruction_resource.py', 34, 'test_create_alembic_process_instruction') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> <_UnixSelectorEventLoop running=False closed=False debug=False> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + pytest_assertrepr_compare [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + op: == + left: 500 + right: 201 + finish pytest_assertrepr_compare --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: > + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_exception_interact [hook] + node: + call: > + report: + finish pytest_exception_interact --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/application/test_alembic_instruction_resource.py::test_create_alembic_process_instruction + location: ('tests/application/test_alembic_instruction_resource.py', 34, 'test_create_alembic_process_instruction') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/application/test_philosophers_stone.py::test_create_philosophers_stone + location: ('tests/application/test_philosophers_stone.py', 5, 'test_create_philosophers_stone') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> <_UnixSelectorEventLoop running=False closed=False debug=False> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/application/test_philosophers_stone.py::test_create_philosophers_stone + location: ('tests/application/test_philosophers_stone.py', 5, 'test_create_philosophers_stone') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/application/test_substance_resource.py::test_create_substance + location: ('tests/application/test_substance_resource.py', 12, 'test_create_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> <_UnixSelectorEventLoop running=False closed=False debug=False> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/application/test_substance_resource.py::test_create_substance + location: ('tests/application/test_substance_resource.py', 12, 'test_create_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/application/test_substance_resource.py::test_get_substances + location: ('tests/application/test_substance_resource.py', 29, 'test_get_substances') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> <_UnixSelectorEventLoop running=False closed=False debug=False> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + pytest_assertrepr_compare [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + op: is + left: + right: + finish pytest_assertrepr_compare --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: is list\n + where = type(None)") tblen=31>> + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_exception_interact [hook] + node: + call: is list\n + where = type(None)") tblen=1>> + report: + finish pytest_exception_interact --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/application/test_substance_resource.py::test_get_substances + location: ('tests/application/test_substance_resource.py', 29, 'test_get_substances') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_can_set_up_my_alembic + location: ('tests/domain/test_alembic.py', 5, 'test_can_set_up_my_alembic') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_can_set_up_my_alembic + location: ('tests/domain/test_alembic.py', 5, 'test_can_set_up_my_alembic') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_can_mix_multiple_substances_in_my_alembic + location: ('tests/domain/test_alembic.py', 8, 'test_can_mix_multiple_substances_in_my_alembic') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_can_mix_multiple_substances_in_my_alembic + location: ('tests/domain/test_alembic.py', 8, 'test_can_mix_multiple_substances_in_my_alembic') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_cannot_mix_one_substance_in_my_alembic + location: ('tests/domain/test_alembic.py', 16, 'test_cannot_mix_one_substance_in_my_alembic') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_cannot_mix_one_substance_in_my_alembic + location: ('tests/domain/test_alembic.py', 16, 'test_cannot_mix_one_substance_in_my_alembic') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_mixing_sulphur_salt_and_mercury_gives_gloop + location: ('tests/domain/test_alembic.py', 23, 'test_mixing_sulphur_salt_and_mercury_gives_gloop') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_mixing_sulphur_salt_and_mercury_gives_gloop + location: ('tests/domain/test_alembic.py', 23, 'test_mixing_sulphur_salt_and_mercury_gives_gloop') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_mixing_other_recipes_gives_sludge + location: ('tests/domain/test_alembic.py', 38, 'test_mixing_other_recipes_gives_sludge') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_mixing_other_recipes_gives_sludge + location: ('tests/domain/test_alembic.py', 38, 'test_mixing_other_recipes_gives_sludge') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_can_process_substance + location: ('tests/domain/test_alembic.py', 58, 'test_can_process_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_can_process_substance + location: ('tests/domain/test_alembic.py', 58, 'test_can_process_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic.py::test_cannot_perform_unknown_process + location: ('tests/domain/test_alembic.py', 74, 'test_cannot_perform_unknown_process') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic.py::test_cannot_perform_unknown_process + location: ('tests/domain/test_alembic.py', 74, 'test_cannot_perform_unknown_process') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_alembic_instruction_handler.py::test_can_set_up_my_alembic_instruction_handler + location: ('tests/domain/test_alembic_instruction_handler.py', 34, 'test_can_set_up_my_alembic_instruction_handler') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> AlembicInstruction(instruction_type='process', natures=['Sludge'], action='cook') [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_alembic_instruction_handler.py::test_can_set_up_my_alembic_instruction_handler + location: ('tests/domain/test_alembic_instruction_handler.py', 34, 'test_can_set_up_my_alembic_instruction_handler') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_pantry.py::test_can_add_to_pantry[list] + location: ('tests/domain/test_pantry.py', 17, 'test_can_add_to_pantry[list]') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> list [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + list: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_pantry.py::test_can_add_to_pantry[list] + location: ('tests/domain/test_pantry.py', 17, 'test_can_add_to_pantry[list]') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_pantry.py::test_can_retrieve_substance_from_pantry_by_nature[list] + location: ('tests/domain/test_pantry.py', 27, 'test_can_retrieve_substance_from_pantry_by_nature[list]') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> list [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + pytest_fixture_setup [hook] + fixturedef: + request: > + finish pytest_fixture_setup --> [hook] + list: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + pytest_fixture_post_finalizer [hook] + fixturedef: + request: > + finish pytest_fixture_post_finalizer --> [] [hook] + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_pantry.py::test_can_retrieve_substance_from_pantry_by_nature[list] + location: ('tests/domain/test_pantry.py', 27, 'test_can_retrieve_substance_from_pantry_by_nature[list]') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_can_cook_substance + location: ('tests/domain/test_substance.py', 2, 'test_can_cook_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_can_cook_substance + location: ('tests/domain/test_substance.py', 2, 'test_can_cook_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_can_wash_substance + location: ('tests/domain/test_substance.py', 9, 'test_can_wash_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_can_wash_substance + location: ('tests/domain/test_substance.py', 9, 'test_can_wash_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_can_pickle_substance + location: ('tests/domain/test_substance.py', 16, 'test_can_pickle_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_can_pickle_substance + location: ('tests/domain/test_substance.py', 16, 'test_can_pickle_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_can_ferment_substance + location: ('tests/domain/test_substance.py', 23, 'test_can_ferment_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_can_ferment_substance + location: ('tests/domain/test_substance.py', 23, 'test_can_ferment_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_can_cook_and_ferment_substance + location: ('tests/domain/test_substance.py', 30, 'test_can_cook_and_ferment_substance') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_can_cook_and_ferment_substance + location: ('tests/domain/test_substance.py', 30, 'test_can_cook_and_ferment_substance') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + pytest_runtest_protocol [hook] + item: + nextitem: None + pytest_runtest_logstart [hook] + nodeid: tests/domain/test_substance.py::test_the_order_of_processes_applied_to_a_substance_matters + location: ('tests/domain/test_substance.py', 38, 'test_the_order_of_processes_applied_to_a_substance_matters') + finish pytest_runtest_logstart --> [] [hook] + pytest_runtest_setup [hook] + item: + finish pytest_runtest_setup --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_call [hook] + item: + pytest_pyfunc_call [hook] + pyfuncitem: + finish pytest_pyfunc_call --> True [hook] + finish pytest_runtest_call --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('passed', '.', 'PASSED') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_teardown [hook] + item: + nextitem: None + finish pytest_runtest_teardown --> [] [hook] + pytest_runtest_makereport [hook] + item: + call: + finish pytest_runtest_makereport --> [hook] + pytest_runtest_logreport [hook] + report: + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('', '', '') [hook] + finish pytest_runtest_logreport --> [] [hook] + pytest_runtest_logfinish [hook] + nodeid: tests/domain/test_substance.py::test_the_order_of_processes_applied_to_a_substance_matters + location: ('tests/domain/test_substance.py', 38, 'test_the_order_of_processes_applied_to_a_substance_matters') + finish pytest_runtest_logfinish --> [] [hook] + finish pytest_runtest_protocol --> True [hook] + finish pytest_runtestloop --> True [hook] + pytest_sessionfinish [hook] + session: testsfailed=3 testscollected=21> + exitstatus: ExitCode.TESTS_FAILED + pytest_terminal_summary [hook] + terminalreporter: <_pytest.terminal.TerminalReporter object at 0x7f780666aee0> + exitstatus: ExitCode.TESTS_FAILED + config: <_pytest.config.Config object at 0x7f78089fd5b0> + early skip of rewriting module: pygments [assertion] + early skip of rewriting module: pygments [assertion] + early skip of rewriting module: pygments [assertion] + early skip of rewriting module: wcwidth [assertion] + early skip of rewriting module: wcwidth.wcwidth [assertion] + early skip of rewriting module: wcwidth.table_wide [assertion] + early skip of rewriting module: wcwidth.table_zero [assertion] + early skip of rewriting module: wcwidth.unicode_versions [assertion] + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + pytest_report_teststatus [hook] + report: + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_report_teststatus --> ('failed', 'F', 'FAILED') [hook] + finish pytest_terminal_summary --> [] [hook] + finish pytest_sessionfinish --> [] [hook] + pytest_unconfigure [hook] + config: <_pytest.config.Config object at 0x7f78089fd5b0> + finish pytest_unconfigure --> [] [hook] diff --git a/022-burette/magnum_opus_iii/requirements.txt b/022-burette/magnum_opus_iii/requirements.txt new file mode 100644 index 0000000..3400e03 --- /dev/null +++ b/022-burette/magnum_opus_iii/requirements.txt @@ -0,0 +1,10 @@ +appdirs +quart +wheel +quart-openapi +flask-marshmallow +flask-sqlalchemy +flask-injector +marshmallow-sqlalchemy +sqlalchemy-utils +ariadne diff --git a/022-burette/magnum_opus_iii/setup.cfg b/022-burette/magnum_opus_iii/setup.cfg new file mode 100644 index 0000000..163e9af --- /dev/null +++ b/022-burette/magnum_opus_iii/setup.cfg @@ -0,0 +1,35 @@ +[metadata] +name = aiomagnumopus +version = 0.0.1 +author = Phil Weir +author_email = phil.weir@flaxandteal.co.uk +license = GPL +description = Service for cooking up a philosopher's stone +long-description = file:README.md + +[options] +include_package_data = True +packages = find: +python_requires = >=3.6 +install_requires = + appdirs + quart-openapi + flask-marshmallow + flask-sqlalchemy + flask-injector + sqlalchemy-utils + marshmallow-sqlalchemy + quart-openapi + wheel + ariadne + +[options.extras_require] +dev = + pytest + pytest-pep8 + pytest-cov + pytest-asyncio + +[options.packages.find] +exclude = + tests diff --git a/022-burette/magnum_opus_iii/setup.py b/022-burette/magnum_opus_iii/setup.py new file mode 100644 index 0000000..1767837 --- /dev/null +++ b/022-burette/magnum_opus_iii/setup.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +""" +Magnum Opus + +This tool performs alchemical reactions to create +the Philosopher's Stone. + +@author: Phil Weir +""" + +from setuptools import setup + +if __name__ == '__main__': + setup() diff --git a/022-burette/magnum_opus_iii/tests/__init__.py b/022-burette/magnum_opus_iii/tests/__init__.py new file mode 100644 index 0000000..c09f99d --- /dev/null +++ b/022-burette/magnum_opus_iii/tests/__init__.py @@ -0,0 +1,4 @@ + +def is_dictionary_inside(d1, d2): + return d1.items() <= d2.items() + diff --git a/022-burette/magnum_opus_iii/tests/application/.coverage b/022-burette/magnum_opus_iii/tests/application/.coverage new file mode 100644 index 0000000..0e5750b Binary files /dev/null and b/022-burette/magnum_opus_iii/tests/application/.coverage differ diff --git a/022-burette/magnum_opus_iii/tests/application/__init__.py b/022-burette/magnum_opus_iii/tests/application/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/022-burette/magnum_opus_iii/tests/application/test_alembic_instruction_resource.py b/022-burette/magnum_opus_iii/tests/application/test_alembic_instruction_resource.py new file mode 100644 index 0000000..d7c7c14 --- /dev/null +++ b/022-burette/magnum_opus_iii/tests/application/test_alembic_instruction_resource.py @@ -0,0 +1,49 @@ +import pytest +from magnumopus import create_app +from .. import is_dictionary_inside +from .test_substance_resource import create_substance_request + +async def create_alembic_instruction_request(client, instruction_type, natures, action=None): + data = { + 'instruction_type': instruction_type, + 'natures': ','.join(natures) + } + + if action is not None: + data['action'] = action + + return await client.post('/alembic_instruction', json=data) + +@pytest.mark.asyncio +async def test_create_alembic_mix_instruction(client): + await create_substance_request(client, 'Mercury') + await create_substance_request(client, 'Salt') + await create_substance_request(client, 'Sulphur') + + rv = await create_alembic_instruction_request(client, 'mix', ['Mercury', 'Salt', 'Sulphur']) + + assert rv.status_code == 201 + + content = await rv.get_json() + + assert is_dictionary_inside({ + 'nature': 'Gloop', + 'state': [], + 'is_philosophers_stone': False + }, content) + +@pytest.mark.asyncio +async def test_create_alembic_process_instruction(client): + await create_substance_request(client, 'Mercury') + + rv = await create_alembic_instruction_request(client, 'process', ['Mercury'], 'cook') + + assert rv.status_code == 201 + + content = await rv.get_json() + + assert is_dictionary_inside({ + 'nature': 'Mercury', + 'state': ['cooked'], + 'is_philosophers_stone': False + }, content) diff --git a/022-burette/magnum_opus_iii/tests/application/test_philosophers_stone.py b/022-burette/magnum_opus_iii/tests/application/test_philosophers_stone.py new file mode 100644 index 0000000..ca25fb7 --- /dev/null +++ b/022-burette/magnum_opus_iii/tests/application/test_philosophers_stone.py @@ -0,0 +1,7 @@ +import pytest +from magnumopus import create_app +from .. import is_dictionary_inside + + +def test_create_philosophers_stone(client): + pass diff --git a/022-burette/magnum_opus_iii/tests/application/test_substance_resource.py b/022-burette/magnum_opus_iii/tests/application/test_substance_resource.py new file mode 100644 index 0000000..28a8ec7 --- /dev/null +++ b/022-burette/magnum_opus_iii/tests/application/test_substance_resource.py @@ -0,0 +1,52 @@ +import pytest +from magnumopus import create_app +from .. import is_dictionary_inside + +async def create_substance_request(client, nature): + return await client.post('/substance', json={ + 'nature': nature + }) + +async def index_substances_request(client, nature): + return await client.get(f'/substance?nature={nature}') + +@pytest.mark.asyncio +async def test_create_substance(client): + rv = await create_substance_request(client, 'Sulphur') + + assert rv.status_code == 201 + + content = await rv.get_json() + + assert type(content['id']) is int + + assert is_dictionary_inside({ + 'nature': 'Sulphur', + 'state': [], + 'is_philosophers_stone': False + }, content) + + +@pytest.mark.asyncio +async def test_get_substances(client): + await create_substance_request(client, 'Sulphur') + + rv = await index_substances_request(client, 'Sulphur') + + assert rv.status_code == 200 + + content = (await rv.get_json())['result'] + + assert type(content) is list + + assert len(content) == 1 + + assert type(content[0]['id']) is int + + assert is_dictionary_inside({ + 'nature': 'Sulphur', + 'state': [], + 'is_philosophers_stone': False + }, content[0]) + +# We also need non-happy paths! diff --git a/022-burette/magnum_opus_iii/tests/conftest.py b/022-burette/magnum_opus_iii/tests/conftest.py new file mode 100644 index 0000000..d810697 --- /dev/null +++ b/022-burette/magnum_opus_iii/tests/conftest.py @@ -0,0 +1,19 @@ +import pytest +from magnumopus import create_app +from magnumopus.repositories.pantry import Pantry + +@pytest.fixture +async def app(): + app = create_app() + await app.startup() + yield app + await app.shutdown() + + +@pytest.fixture +async def client(app): + pantry = app.extensions['injector'].get(Pantry) + pantry.empty_pantry() + async with app.test_client() as client: + yield client + pantry.empty_pantry() diff --git a/022-burette/magnum_opus_iii/tests/domain/__init__.py b/022-burette/magnum_opus_iii/tests/domain/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/022-burette/magnum_opus_iii/tests/domain/test_alembic.py b/022-burette/magnum_opus_iii/tests/domain/test_alembic.py new file mode 100644 index 0000000..cd67657 --- /dev/null +++ b/022-burette/magnum_opus_iii/tests/domain/test_alembic.py @@ -0,0 +1,81 @@ +import pytest + +from magnumopus.services.alembic import Alembic, NotEnoughSubstancesToMixException, UnknownProcessException +from magnumopus.models.substance import Substance + +def test_can_set_up_my_alembic(): + Alembic() + +def test_can_mix_multiple_substances_in_my_alembic(): + alembic = Alembic() + substance = [Substance() for _ in range(3)] + alembic.mix(*substance) + + substance = [Substance() for _ in range(6)] + alembic.mix(*substance) + +def test_cannot_mix_one_substance_in_my_alembic(): + alembic = Alembic() + substance = Substance() + + with pytest.raises(NotEnoughSubstancesToMixException): + alembic.mix(substance) + +def test_mixing_sulphur_salt_and_mercury_gives_gloop(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + + result = alembic.mix(sulphur, salt, mercury) + + assert result.nature == 'Gloop' + + result = alembic.mix(mercury, sulphur, salt) + + assert result.nature == 'Gloop' + +def test_mixing_other_recipes_gives_sludge(): + alembic = Alembic() + + sulphur = Substance(nature='Sulphur') + salt = Substance(nature='Salt') + mercury = Substance(nature='Mercury') + gloop = Substance(nature='Gloop') + + result = alembic.mix(sulphur, salt, mercury, sulphur) + + assert result.nature == 'Sludge' + + result = alembic.mix(salt, mercury) + + assert result.nature == 'Sludge' + + result = alembic.mix(gloop, salt, mercury) + + assert result.nature == 'Sludge' + +def test_can_process_substance(): + alembic = Alembic() + + substance = Substance() + result = alembic.process('cook', substance) + + substance = Substance() + cooked_substance = substance.cook() + + assert result.state == cooked_substance.state + + result = alembic.process('ferment', substance) + cooked_fermented_substance = cooked_substance.ferment() + + assert result.state == cooked_fermented_substance.state + +def test_cannot_perform_unknown_process(): + alembic = Alembic() + + substance = Substance() + + with pytest.raises(UnknownProcessException): + alembic.process('boil', substance) diff --git a/022-burette/magnum_opus_iii/tests/domain/test_alembic_instruction_handler.py b/022-burette/magnum_opus_iii/tests/domain/test_alembic_instruction_handler.py new file mode 100644 index 0000000..ccb2f96 --- /dev/null +++ b/022-burette/magnum_opus_iii/tests/domain/test_alembic_instruction_handler.py @@ -0,0 +1,37 @@ +import pytest + +from magnumopus.services.alembic_instruction_handler import AlembicInstruction, AlembicInstructionHandler +from magnumopus.repositories.list_pantry import ListPantry +from magnumopus.models.substance import Substance + +@pytest.fixture +def instruction_unknown(): + return AlembicInstruction( + 'saute', + ['Sulphur'], + 'cook' + ) + +@pytest.fixture +def instruction(): + return AlembicInstruction( + 'process', + ['Sludge'], + 'cook' + ) + +@pytest.fixture +def pantry(): + pantry = ListPantry() + + substance = Substance(nature='Sludge') + pantry.add_substance(substance) + + substance = Substance(nature='Sulphur') + pantry.add_substance(substance) + + return pantry + +def test_can_set_up_my_alembic_instruction_handler(instruction, pantry): + handler = AlembicInstructionHandler() + handler.handle(instruction, pantry) diff --git a/022-burette/magnum_opus_iii/tests/domain/test_pantry.py b/022-burette/magnum_opus_iii/tests/domain/test_pantry.py new file mode 100644 index 0000000..0dc5010 --- /dev/null +++ b/022-burette/magnum_opus_iii/tests/domain/test_pantry.py @@ -0,0 +1,38 @@ +import pytest + +from magnumopus.repositories.list_pantry import ListPantry +from magnumopus.models.substance import Substance + +@pytest.fixture +def list_pantry(): + return ListPantry() + +@pytest.fixture +@pytest.mark.asyncio +def pantries(list_pantry): + return { + 'list': list_pantry + } + +# We may want other pantry-specific tests, but bear in mind LSP +@pytest.mark.parametrize('pantry_type', ['list']) +def test_can_add_to_pantry(pantry_type, pantries): + pantry = pantries[pantry_type] + + substance = Substance() + + pantry.add_substance(substance) + + assert pantry.count_all_substances() == 1 + +@pytest.mark.parametrize('pantry_type', ['list']) +def test_can_retrieve_substance_from_pantry_by_nature(pantry_type, pantries): + pantry = pantries[pantry_type] + + substance = Substance(nature='Mercury') + + pantry.add_substance(substance) + + mercury = pantry.find_substances_by_nature('Mercury')[0] + + assert mercury.nature == 'Mercury' diff --git a/022-burette/magnum_opus_iii/tests/domain/test_substance.py b/022-burette/magnum_opus_iii/tests/domain/test_substance.py new file mode 100644 index 0000000..d00a6f7 --- /dev/null +++ b/022-burette/magnum_opus_iii/tests/domain/test_substance.py @@ -0,0 +1,49 @@ +from magnumopus.models.substance import Substance + +def test_can_cook_substance(): + substance = Substance() + + result = substance.cook() + + assert substance.state == ['cooked'] + +def test_can_wash_substance(): + substance = Substance() + + result = substance.wash() + + assert result.state == ['washed'] + +def test_can_pickle_substance(): + substance = Substance() + + result = substance.pickle() + + assert result.state == ['pickled'] + +def test_can_ferment_substance(): + substance = Substance() + + result = substance.ferment() + + assert substance.state == ['fermented'] + +def test_can_cook_and_ferment_substance(): + substance = Substance() + + result = substance.cook() + result = result.ferment() + + assert substance.state == ['cooked', 'fermented'] + +def test_the_order_of_processes_applied_to_a_substance_matters(): + substance1 = Substance() + result1 = substance1.cook() + result1 = result1.ferment() + + substance2 = Substance() + result2 = substance2.ferment() + result2 = result2.cook() + + assert result1.state != result2.state + assert result1.state == result2.state[::-1] diff --git a/022-burette/magnum_opus_iii/tox.ini b/022-burette/magnum_opus_iii/tox.ini new file mode 100644 index 0000000..d815853 --- /dev/null +++ b/022-burette/magnum_opus_iii/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist = py38 + +[testenv] +deps = pytest +commands = pytest