def test_cultivar_bad_slugs(self, app, db): """Return 404 if any slug given does not correspond to a db entry.""" app.config["SHOW_CULTIVAR_PAGES"] = True idx = Index() cn = CommonName() cultivar = Cultivar() db.session.add_all([idx, cn, cultivar]) idx.name = "Perennial Flower" cn.name = "Foxglove" cultivar.name = "Foxy" cultivar.common_name = cn cultivar.description = "Like that Hendrix song." db.session.commit() with app.test_client() as tc: rv = tc.get(url_for("seeds.cultivar", idx_slug=idx.slug, cn_slug=cn.slug, cv_slug="no-biscuit")) assert rv.status_code == 404 with app.test_client() as tc: rv = tc.get(url_for("seeds.cultivar", idx_slug="no_biscuit", cn_slug=cn.slug, cv_slug=cultivar.slug)) assert rv.status_code == 404 with app.test_client() as tc: rv = tc.get(url_for("seeds.cultivar", idx_slug=idx.slug, cn_slug="no-biscuit", cv_slug=cultivar.slug)) assert rv.status_code == 404 with app.test_client() as tc: rv = tc.get(url_for("seeds.cultivar", idx_slug="no-biscuit", cn_slug="no-biscuit", cv_slug="no-biscuit")) assert rv.status_code == 404
def test_add_cultivar_successful_submit_no_stock_and_inactive(self, mock_save, app, db): """Flash messages if cultivar is not in stock and has been dropped.""" bn = BotanicalName() cn = CommonName() idx = Index() db.session.add_all([bn, cn, idx]) bn.name = "Digitalis purpurea" idx.name = "Perennial Flower" cn.name = "Foxglove" cn.index = idx bn.common_names.append(cn) db.session.commit() with app.test_client() as tc: rv = tc.post( url_for("seeds.add_cultivar", cn_id=cn.id), data=dict( botanical_name=str(bn.id), index=str(idx.id), description="Very foxy.", active="", in_stock="", name="Foxy", section="0", thumbnail=(io.BytesIO(b"fawks"), "foxy.jpg"), ), follow_redirects=True, ) assert '"Foxy Foxglove" is not in stock' in str(rv.data) assert '"Foxy Foxglove" is currently inactive' in str(rv.data)
def test_queryable_dict(self): """Return a dict containing the name and index of a CommonName.""" cn = CommonName() assert cn.queryable_dict == {'Common Name': None, 'Index': None} cn.name = 'Foxglove' assert cn.queryable_dict == {'Common Name': 'Foxglove', 'Index': None} cn.index = Index(name='Perennial') assert cn.queryable_dict == {'Common Name': 'Foxglove', 'Index': 'Perennial'}
def test_remove_common_name_renders_page(self, app, db): """Render seeds/remove_common_name.html given valid cn_id.""" cn = CommonName() db.session.add(cn) cn.name = "Coleus" db.session.commit() with app.test_client() as tc: rv = tc.get(url_for("seeds.remove_common_name", cn_id=cn.id)) assert rv.status_code == 200 assert "Remove Common Name" in str(rv.data)
def test_init(self, m_sfc): m_sfc.return_value = [(1, "One"), (2, "Two"), (3, "Three")] cn1 = CommonName(name="One") cn1.id = 1 cn2 = CommonName(name="Two") cn2.id = 2 obj = BotanicalName(name="Bot nam") obj.common_names = [cn1, cn2] ebnf = EditBotanicalNameForm(obj=obj) assert ebnf.common_names.data == [1, 2]
def test_html_botanical_names_with_bns(self): """Return a list of botanical names formatted for use on webpage.""" cn = CommonName(name='Foxglove') cn.botanical_names = [BotanicalName(name='Digitalis purpurea'), BotanicalName(name='Digitalis über alles'), BotanicalName(name='Digitalis does dallas')] assert cn.html_botanical_names == ( 'Digitalis purpurea, ' '<abbr title="Digitalis">D.</abbr> über alles, ' '<abbr title="Digitalis">D.</abbr> does dallas' )
def test_queryable_dicts_to_json_bad_args(self): """Raise a TypeError if any objects lack the lookup_dict method.""" with pytest.raises(TypeError): queryable_dicts_to_json((1, 2, 3)) cn1 = CommonName(name='Foxglove') cn1.index = Index(name='Perennial') cn2 = CommonName(name='Coleus') cn2.index = Index(name='Annual') idx = Index(name='Has no lookup_dict') with pytest.raises(TypeError): queryable_dicts_to_json((cn1, cn2, idx))
def test_common_name_bad_slugs(self, app, db): """Give a 404 page if given malformed cn_slug and idx_slug.""" cn = CommonName() idx = Index() db.session.add_all([cn, idx]) cn.name = "Foxglove" idx.name = "Perennial Flower" db.session.commit() with app.test_client() as tc: rv = tc.get(url_for("seeds.common_name", idx_slug="pewennial-flower", cn_slug="fawksglove")) assert rv.status_code == 404
def test_select_common_name_success(self, app, db): """Redirect to dest with cn_id selected by form.""" cn = CommonName() db.session.add(cn) cn.name = "Coleus" db.session.commit() with app.test_client() as tc: rv = tc.post( url_for("seeds.select_common_name", dest="seeds.edit_common_name"), data=dict(common_name=cn.id) ) assert rv.status_code == 302 assert rv.location == url_for("seeds.edit_common_name", cn_id=cn.id, _external=True)
def test_add_botanical_name_bad_cn_id(self, app, db): """Redirect to select common name if CommonName can't be loaded.""" with app.test_client() as tc: rv = tc.get(url_for("seeds.add_botanical_name")) assert rv.location == url_for("seeds.select_common_name", dest="seeds.add_botanical_name", _external=True) cn = CommonName() cn.id = 1 db.session.add(cn) db.session.commit() with app.test_client() as tc: rv = tc.get(url_for("seeds.add_botanical_name", cn_id=42)) assert rv.location == url_for("seeds.select_common_name", dest="seeds.add_botanical_name", _external=True)
def test_add_section_bad_cn_id(self, app, db): """Redirect to select_common_name if cn_id is invalid.""" with app.test_client() as tc: rv = tc.get(url_for("seeds.add_section")) assert rv.location == url_for("seeds.select_common_name", dest="seeds.add_section", _external=True) cn = CommonName(name="Foxglove") cn.id = 1 db.session.add(cn) db.session.commit() with app.test_client() as tc: rv = tc.get(url_for("seeds.add_section", cn_id=42)) assert rv.location == url_for("seeds.select_common_name", dest="seeds.add_section", _external=True)
def test_common_name_renders_page(self, app, db): """Render page with common name info given valid slugs.""" cn = CommonName() idx = Index() db.session.add_all([cn, idx]) cn.name = "Foxglove" cn.description = "Do foxes really wear these?" idx.name = "Perennial Flower" cn.index = idx db.session.commit() with app.test_client() as tc: rv = tc.get(url_for("seeds.common_name", idx_slug=idx.slug, cn_slug=cn.slug)) assert "Do foxes really wear these?" in str(rv.data)
def test_gw_from_dict_(self, db): """Set grows_with with a list of ids from a CommonName.dict_""" a = CommonName(name='a') b = CommonName(name='b') c = CommonName(name='c') db.session.add_all([a, b, c]) db.session.flush() cn = CommonName(name='Test') cn.gw_common_names = [a, b, c] d = cn.dict_ cn2 = CommonName(name='Test2') cn2.gw_from_dict_(d) assert cn.gw_common_names == cn2.gw_common_names
def test_add_one_with_synonyms(self): """Add a BotanicalName with synonyms to Botanical Names sheet.""" wb = Workbook() ws = wb.active bnws = BotanicalNamesWorksheet(ws) bnws.setup() bn = BotanicalName(name='Innagada davida') cn = CommonName(name='Rock') cn.index = Index(name='Music') bn.common_names = [cn] bn.synonyms_string = 'Iron butterfly' bnws.add_one(bn) assert bnws.cell(2, bnws.cols['Synonyms']).value == 'Iron butterfly'
def test_gw_from_dict_missing_cns(self, db): """Raise a RuntimeError if any needed CNs are missing.""" a = CommonName(name='a') b = CommonName(name='b') c = CommonName(name='c') db.session.add_all([a, b, c]) db.session.flush() cn = CommonName(name='Test') cn.gw_common_names = [a, b, c] d = cn.dict_ d['gw_common_names'].append(42) cn2 = CommonName(name='Test2') with pytest.raises(RuntimeError): cn2.gw_from_dict_(d)
def test_validate_botanical_name_id(self, m_bnq): """Raise error if selected BN is not in selected CN.""" bn = BotanicalName("Digitalis über alles") cn1 = CommonName(name="Fauxglove") cn1.id = 1 cn2 = CommonName(name="Spuriousglove") cn2.id = 2 bn.common_names = [cn1, cn2] m_bnq.return_value = bn self = mock.MagicMock() self.common_name_id.data = 3 field = mock.MagicMock() with pytest.raises(ValidationError): EditCultivarForm.validate_botanical_name_id(self=self, field=field)
def set_related_links(): with open('/tmp/related_links.json', 'r', encoding='utf-8') as ifile: dicts = json.loads(ifile.read()) print('Setting related links/grows with...') for d in dicts: cn = CommonName.from_slugs( d['source']['idx_slug'], d['source']['cn_slug'] ) if d['target']['anchor']: t = Cultivar.from_slugs( d['target']['idx_slug'], d['target']['cn_slug'], d['target']['anchor'] ) if t: cn.gw_cultivars.append(t) else: t = Section.from_slugs( d['target']['idx_slug'], d['target']['cn_slug'], d['target']['anchor'] ) if t: cn.gw_sections.append(t) else: print( 'Could not find a Section or Cultivar with the ' 'slug: "{}"'.format(d['target']['anchor']) ) t = CommonName.from_slugs( d['target']['idx_slug'], d['target']['cn_slug'] ) cn.gw_common_names.append(t) else: t = CommonName.from_slugs( d['target']['idx_slug'], d['target']['cn_slug'] ) if t: cn.gw_common_names.append(t) else: print('Could not find gw for {}'.format(d)) if t: print( '"{}" grows with the {} "{}"' .format(cn.name, t.__class__.__name__, t.name) ) db.session.commit()
def foxy_cultivar(): """Generate a Cultivar object based on Foxy Foxglove.""" cultivar = Cultivar() cultivar.name = "Foxy" cultivar.description = "Not to be confused with that Hendrix song." bn = BotanicalName() bn.name = "Digitalis purpurea" cultivar.botanical_name = bn idx = Index() idx.name = "Perennial Flower" cn = CommonName() cn.name = "Foxglove" cn.index = idx cultivar.common_name = cn return cultivar
def test_get_or_create_get(self, db): cn = CommonName(name='Foxglove', index=Index(name='Perennial')) db.session.add(cn) db.session.commit() assert CommonName.get_or_create(name='Foxglove', index='Perennial') is cn assert not cn.created
def generate_common_names(idx, l): for d in l: cn = CommonName.get_or_create(d['name'], idx) db.session.add(cn) cn.list_as = d['list_as'] cn.slug = d['slug'] cn.subtitle = d['subtitle'] cn.sunlight = d['sunlight'] cn.thumbnail = download_image(d['thumb_url']) cn.botanical_names = d['botanical_names'] cn.description = d['description'] cn.instructions = d['instructions'] if not cn.cultivars: cn.cultivars = [] for cv in generate_cultivars(cn, d['cultivars']): if cv not in cn.cultivars: cn.cultivars.append(cv) if not cn.sections: cn.sections = [] for s in generate_sections(cn, d['sections']): if s not in cn.sections: cn.sections.append(s) db.session.flush() cn.child_sections.reorder() cn.child_cultivars.reorder() yield cn
def test_add_one_with_optionals(self): """Add a common name with optionals to Common Names sheet.""" wb = Workbook() ws = wb.active cnws = CommonNamesWorksheet(ws) cnws.setup() cn = CommonName(name='Foxglove', description='Spotty.', instructions='Just add water!') cn.index = Index(name='Perennial') cn.synonyms_string = 'Digitalis' cnws.add_one(cn) assert cnws.cell(2, cnws.cols['Description']).value == 'Spotty.' assert cnws.cell( 2, cnws.cols['Planting Instructions'] ).value == 'Just add water!' assert cnws.cell(2, cnws.cols['Synonyms']).value == 'Digitalis'
def test_get_or_create_create_with_existing_index(self, db): idx = Index(name='Perennial') db.session.add(idx) db.session.commit() cn = CommonName.get_or_create(name='Foxglove', index='Perennial') assert cn.created assert cn.index is idx assert not idx.created
def save_row_to_db(self, row, stream=sys.stdout): """Save a row from the Common Names sheet to the database. Args: row: The number of the row to save. stream: Optional IO stream to print messages to. Returns: bool: `True` if changes have been made, `False` if not. """ cn_json = self.cell(row, self.cols['Common Name (JSON)']).value cn_dict = json.loads(cn_json) section = dbify(self.cell(row, self.cols['Section']).value) description = self.cell(row, self.cols['Description']).value print('-- BEGIN editing/creating Section \'{0}\' from row #{1}. ' '--'.format(section, row), file=stream) edited = False cn = CommonName.get_or_create(name=dbify(cn_dict['Common Name']), index=dbify(cn_dict['Index']), stream=stream) sec = None if not cn.created: sec = Section.query\ .filter(Section.name == section, Section.common_name_id == cn.id)\ .one_or_none() if sec: print('The Section \'{0}\' has been loaded from the database.' .format(sec.name), file=stream) else: edited = True sec = Section(name=section) sec.common_name = cn print('CommonName for the Section \'{0}\' set to: {1}' .format(sec.name, cn.name), file=stream) db.session.add(sec) print('The Section \'{0}\' does not yet exist in the database, ' 'so it has been created.'.format(sec.name), file=stream) if description != sec.description: edited = True if description: sec.description = description print('Description for the Section \'{0}\' set to: {1}' .format(sec.name, sec.description), file=stream) else: sec.description = None print('Description for the Section \'{0}\' has been cleared.' .format(sec.name), file=stream) if edited: db.session.flush() print('Changes to the Section \'{0}\' have been flushed to ' 'the database.'.format(sec.name), file=stream) else: print('No changes were made to the Section \'{0}\'.' .format(sec.name), file=stream) print('-- END editing/creating Section \'{0}\' from row #{1}. ' '--'.format(sec.name, row), file=stream) return edited
def test_add_one_no_optionals(self): """Add a common name (with no optional data) to Common Names sheet.""" messages = StringIO() wb = Workbook() ws = wb.active cnws = CommonNamesWorksheet(ws) cnws.setup() cn = CommonName(name='Foxglove') cn.index = Index(name='Perennial') cnws.add_one(cn, stream=messages) assert cnws.cell(2, cnws.cols['Index']).value == 'Perennial' assert cnws.cell(2, cnws.cols['Common Name']).value == 'Foxglove' assert cnws.cell(2, cnws.cols['Description']).value is None assert cnws.cell(2, cnws.cols['Planting Instructions']).value is None assert cnws.cell(2, cnws.cols['Synonyms']).value is None messages.seek(0) msgs = messages.read() assert ('Adding data from <CommonName "Foxglove"> to row #2 of ' 'common names worksheet.') in msgs
def test_remove_common_name_not_verified(self, app, db): """Redirect to self with flash if verify_removal not checked.""" cn = CommonName() cn2 = CommonName() db.session.add_all([cn, cn2]) cn.name = "Coleus" cn2.name = "Kingus" db.session.commit() assert cn in CommonName.query.all() with app.test_client() as tc: rv = tc.post(url_for("seeds.remove_common_name", cn_id=cn.id), data=dict(verify_removal="", move_to=cn2.id)) assert rv.location == url_for("seeds.remove_common_name", cn_id=cn.id, _external=True) with app.test_client() as tc: rv = tc.post( url_for("seeds.remove_common_name", cn_id=cn.id), data=dict(verify_removal="", move_to=cn2.id), follow_redirects=True, ) assert "Common name was not removed" in str(rv.data) assert cn in CommonName.query.all()
def test_cv_slugs_not_in_cultivar(self, app, db): """Return 404 if slugs return db entries, but entry not in cultivar.""" app.config["SHOW_CULTIVAR_PAGES"] = True idx1 = Index() idx2 = Index() cn1 = CommonName() cn2 = CommonName() cultivar = Cultivar() db.session.add_all([idx1, idx2, cn1, cn2, cultivar]) idx1.name = "Perennial Flower" idx2.name = "Long Hair" cn1.name = "Foxglove" cn2.name = "Persian" cultivar.name = "Foxy" cultivar.common_name = cn1 db.session.commit() with app.test_client() as tc: rv = tc.get(url_for("seeds.cultivar", idx_slug=idx1.slug, cn_slug=cn2.slug, cv_slug=cultivar.slug)) assert rv.status_code == 404 with app.test_client() as tc: rv = tc.get(url_for("seeds.cultivar", idx_slug=idx2.slug, cn_slug=cn1.slug, cv_slug=cultivar.slug)) assert rv.status_code == 404
def test_add_one_no_optionals(self): """Add a BotanicalName object to Botanical Names sheet.""" messages = StringIO() wb = Workbook() ws = wb.active bnws = BotanicalNamesWorksheet(ws) bnws.setup() bn = BotanicalName(name='Innagada davida') cn = CommonName(name='Rock') cn.index = Index(name='Music') bn.common_names = [cn] bnws.add_one(bn, stream=messages) assert bnws.cell( 2, bnws.cols['Common Names (JSON)'] ).value == queryable_dicts_to_json([cn]) assert bnws.cell( 2, bnws.cols['Botanical Name'] ).value == 'Innagada davida' assert bnws.cell(2, bnws.cols['Synonyms']).value is None messages.seek(0) msgs = messages.read() assert ('Adding data from <BotanicalName "Innagada davida"> to row ' '#2 of botanical names worksheet.') in msgs
def test_queryable_dicts_to_json(self): """Generate a JSON string for looking up Grows With cns/cvs. It can take either, as both have the queryable_dict method. """ gwcn1 = CommonName(name='Foxglove') gwcn1.index = Index(name='Perennial') assert queryable_dicts_to_json([gwcn1]) == \ json.dumps((gwcn1.queryable_dict,)) gwcn2 = CommonName(name='Butterfly Weed') gwcn2.index = Index(name='Perennial') assert queryable_dicts_to_json([gwcn1, gwcn2]) == \ json.dumps((gwcn1.queryable_dict, gwcn2.queryable_dict)) gwcv1 = Cultivar(name='Soulmate') gwcv1.common_name = CommonName(name='Butterfly Weed') gwcv1.common_name.index = Index(name='Perennial') assert queryable_dicts_to_json([gwcv1]) == \ json.dumps((gwcv1.queryable_dict,)) gwcv2 = Cultivar(name='Petra') gwcv2.common_name = CommonName(name='Foxglove') gwcv2.common_name.index = Index(name='Perennial') gwcv2.section = Section(name='Polkadot') assert queryable_dicts_to_json([gwcv1, gwcv2]) == \ json.dumps((gwcv1.queryable_dict, gwcv2.queryable_dict))
def test_dict__to_from_dict_(self, m_iq, m_cq): """Create new CommonName equal to CN.dict_ Note: grows_with is excluded because that must be handled by a different function. """ m_cq.get.return_value = None cn = CommonName() idx = Index() m_iq.get.return_value = idx idx.id = 1 cn.id = 42 cn.index = idx cn.name = 'Annual' cn.slug = 'annual' cn.description = 'Not built to last.' cn.instructions = 'Plant them.' cn.visible = True d = cn.dict_ assert CommonName.from_dict_(d)
def test_remove_common_name_verified(self, app, db): """Delete CommonName from db on successful submit.""" cn = CommonName() cn2 = CommonName() idx = Index(name="Perennial") db.session.add_all([idx, cn, cn2]) cn.name = "Coleus" cn.index = idx cn2.name = "Kingus" cn2.index = idx db.session.commit() assert cn in CommonName.query.all() with app.test_client() as tc: tc.post( url_for("seeds.remove_common_name", cn_id=cn.id), data=dict(verify_removal=True, move_to=cn2.id), follow_redirects=True, ) assert cn not in CommonName.query.all()