def coverage_stop(self, features, marker): """ Stop the coverage measurement and create report """ self.coverage.stop() self.coverage.combine() self.coverage.save() self.coverage.report(file=sys.stdout) if world.config.cover_html: self.coverage.html_report(directory=world.config.cover_html) if world.config.cover_xml: self.coverage.xml_report(outfile=world.config.cover_xml) if world.config.cover_min_percentage: report = StringIO() self.coverage.report(file=report) match = re.search(r'^TOTAL\s+(.*)$', report.getvalue(), re.MULTILINE) if not match: raise RadishError('Failed to find total percentage in coverage report') total_percentage = int(match.groups()[0].split()[-1][:-1]) if total_percentage < int(world.config.cover_min_percentage): raise RadishError('Failed to reach minimum expected coverage of {0}% (reached: {1}%)'.format( world.config.cover_min_percentage, total_percentage))
def __new__( mcs, name: str, bases: Tuple[Type], classdict: Dict[str, Any], ): resources = { attr: value for attr, value in classdict.items() if isinstance(value, _ResourceDescriptor) } for left, right in combinations(resources.values(), 2): if left.db == right.db and left.prefix == right.prefix: raise RadishError( "There are namespace conflicts in the specified resources. Please " f"provide explicit prefix parameters. Resources: {left}, {right}" ) for attr in resources: del classdict[attr] if "_meta" in classdict: raise RadishError( "'_meta' is a reserved class property for `Interface` classes") cls: InterfaceMeta = cast(InterfaceMeta, type.__new__(mcs, name, bases, classdict)) cls._meta = {"resources": resources} return cls
def serialize(self, instance: Model) -> bytes: """Serialize a model instance to be stored in Redis. :raises: :exc:`~radish.exceptions.RadishError` if the model instance is of an incorrect type. """ if not type(instance) is self.model: if not isinstance(instance, self.model): raise RadishError( "Instance type {type(instance)} does not match resource schema. " f"Accepts {self.model}.") raise RadishError( f"Subclasses of {self.model} are not supported, as they will not " "be deserialized correctly.") return instance.json().encode("utf-8")
def __init__(self): try: from lxml import etree except ImportError: raise RadishError('if you want to use the JUnit xml writer you have to "pip install radish-bdd[junit-xml]"') after.all(self.generate_junit_xml)
def _validate(self): """ Checks if the step is valid to run or not """ if not self.definition_func or not callable(self.definition_func): raise RadishError( "The step '{0}' does not have a step definition".format( self.sentence))
def failure_inspector(self, step): """ Starts a python shell after a step failed """ if step.state is not Step.State.FAILED: return try: from IPython import embed except ImportError as e: raise RadishError( "Cannot import IPython embed function: {0}".format(e)) embed()
def process_user_data(self): """ Process the user data """ if self._cli_user_data: for pair in self._cli_user_data: try: key, value = map(str.strip, self._kv_regex.split(pair, maxsplit=1)) except ValueError as e: msg = "-u/--user-data: User data is invalid. Expecting: 'key=value' Got: '{0}'" raise RadishError(msg.format(pair)) # Allowing all keys and values, even if empty world.config.user_data[key] = value
def failure_inspector(self, step): """ Starts a python shell after a step failed """ if step.state is not Step.State.FAILED: return try: from IPython import embed except ImportError as e: raise RadishError( 'if you want to use the failure inspector extension you have to "pip install radish-bdd[ipython-debugger]"' ) embed()
def __init__(self): try: from coverage import Coverage except ImportError: raise RadishError( 'if you want to use the code coverage you have to "pip install radish-bdd[coverage]"' ) before.all(self.coverage_start) after.all(self.coverage_stop) if world.config.cover_packages: self.cover_packages = world.config.cover_packages.split(",") else: self.cover_packages = [] self.coverage = None self.modules_on_init = set(sys.modules.keys())
def __call__(self, **filter_kwargs) -> Callable[[Model], bool]: bad_kwargs = set(filter_kwargs) - set(self.target_model.__fields__) if bad_kwargs: raise RadishError( f"Invalid filter fields for {self.target_model}: {bad_kwargs}." ) field_filters = { attr: value if callable(value) else equals(value) for attr, value in filter_kwargs.items() } def filter_func(instance: Model): return all( field_filter(getattr(instance, attr)) for attr, field_filter in field_filters.items()) return filter_func
async def save(self, *instances: Model, allow_update: bool = True, expire: SupportsFloat = None) -> None: """Store one or more model instances in the Redis cache. .. code:: python await redis.users.save(User(id=1, name="bob"), User(id=2, name="frank")) :param instances: The set of model instances to store in the cache. :param allow_update: Whether to allow updates to existing records. :param expire: The number of seconds in which to expire te records. """ if not allow_update: existing: List[bool] = await asyncio.gather(*[ self.connection.exists(self.descriptor.get_key(instance)) for instance in instances ]) if any(existing): already_exists: List[Model] = [ instance for instance, exists in zip(instances, existing) if exists ] raise RadishError( f"Records for {repr(already_exists)} already exists") serialized_instances = [(self.descriptor.get_key(instance), self.descriptor.serialize(instance)) for instance in instances] await asyncio.gather(*[ self.connection.set(key, data, pexpire=int(float(expire) * 1000) if expire else None) for key, data in serialized_instances ])
def generate_ccjson(self, features, marker): """ Generates the cucumber json """ if not features: raise RadishError( "No features given to generate cucumber json file") duration = timedelta() for feature in features: if feature.state in [Step.State.PASSED, Step.State.FAILED]: duration += feature.duration ccjson = [] for feature in features: if not feature.has_to_run(world.config.scenarios): continue feature_description = "\n".join(feature.description) feature_json = { "uri": feature.path, "type": "feature", "keyword": feature.keyword, "id": str(feature.id), "name": feature.sentence, "line": feature.line, "description": feature_description, "tags": [], "elements": [] } for i, j in enumerate(feature.tags): feature_json["tags"].append({ "name": "@" + j.name, "line": feature.line - len(feature.tags) + i }) for scenario in ( s for s in feature.all_scenarios if not isinstance(s, (ScenarioOutline, ScenarioLoop))): if not scenario.has_to_run(world.config.scenarios): continue scenario_json = { "keyword": scenario.keyword, "type": "scenario", "id": str(scenario.id), "name": scenario.sentence, "line": scenario.line, "description": "", "steps": [], "tags": [] } start_line_no = scenario.line - len(scenario.tags) for i, tag in enumerate(scenario.tags): scenario_json["tags"].append({ "name": "@" + tag.name, "line": start_line_no + i }) for step in scenario.all_steps: # round duration to 10 decimal points, to avoid it being # printed in scientific notation duration = "%.10f" % step.duration.total_seconds() \ if step.starttime and step.endtime else "0.0" step_json = { "keyword": step.sentence.split()[0], "name": step.sentence, "line": step.line, "result": { "status": step.state, "duration": duration } } if step.state is Step.State.FAILED: step_json["result"][ "error_message"] = step.failure.reason if step.state is Step.State.UNTESTED: step_json["result"]["status"] = "skipped" scenario_json["steps"].append(step_json) feature_json["elements"].append(scenario_json) ccjson.append(feature_json) with open(world.config.cucumber_json, "w+") as f: content = json.dumps(ccjson, indent=4, sort_keys=True) f.write(content)
def generate_junit_xml(self, features, marker): """ Generates the junit xml """ from lxml import etree if not features: raise RadishError("No features given to generate JUnit xml file") duration = timedelta() for feature in features: if feature.state in [Step.State.PASSED, Step.State.FAILED]: duration += feature.duration testsuites_element = etree.Element( "testsuites", time="%.3f" % duration.total_seconds() ) for feature in features: if not feature.has_to_run(world.config.scenarios): continue testsuite_states = {"failures": 0, "errors": 0, "skipped": 0, "tests": 0} for scenario in ( s for s in feature.all_scenarios if not isinstance(s, (ScenarioOutline, ScenarioLoop)) ): if not scenario.has_to_run(world.config.scenarios): continue testsuite_states["tests"] += 1 if scenario.state in [ Step.State.UNTESTED, Step.State.PENDING, Step.State.SKIPPED, ]: testsuite_states["skipped"] += 1 if scenario.state is Step.State.FAILED: testsuite_states["failures"] += 1 testsuite_element = etree.Element( "testsuite", name=feature.sentence, failures=str(testsuite_states["failures"]), errors=str(testsuite_states["errors"]), skipped=str(testsuite_states["skipped"]), tests=str(testsuite_states["tests"]), time="%.3f" % feature.duration.total_seconds(), ) for scenario in ( s for s in feature.all_scenarios if not isinstance(s, (ScenarioOutline, ScenarioLoop)) ): if not scenario.has_to_run(world.config.scenarios): continue testcase_element = etree.Element( "testcase", classname=feature.sentence, name=scenario.sentence, time="%.3f" % scenario.duration.total_seconds(), ) if scenario.state in [ Step.State.UNTESTED, Step.State.PENDING, Step.State.SKIPPED, ]: skipped_element = etree.Element("skipped") testcase_element.append(skipped_element) if scenario.state is Step.State.FAILED: steps_sentence = [] for step in scenario.all_steps: step_element = self._get_element_from_model("step", step) steps_sentence.append(step.sentence) if step.state is Step.State.FAILED: failure_element = etree.Element( "failure", type=step.failure.name, message=step.sentence ) failure_element.text = etree.CDATA( "%s\n\n%s" % ( "\n".join(steps_sentence), self._strip_ansi(step.failure.traceback), ) ) testcase_element.append(failure_element) testsuite_element.append(testcase_element) testsuites_element.append(testsuite_element) with open(world.config.junit_xml, "w+") as f: content = etree.tostring( testsuites_element, pretty_print=True, xml_declaration=True, encoding="utf-8", ) try: if not isinstance(content, str): content = content.decode("utf-8") except Exception: pass finally: f.write(content)
def generate_bdd_xml(self, features, marker): """ Generates the bdd xml """ from lxml import etree if not features: raise RadishError("No features given to generate BDD xml file") duration = timedelta() for feature in features: if feature.state in [Step.State.PASSED, Step.State.FAILED]: duration += feature.duration testrun_element = etree.Element( "testrun", starttime=utils.datetime_to_str(features[0].starttime), endtime=utils.datetime_to_str(features[-1].endtime), duration=str(duration.total_seconds()), agent="{0}@{1}".format(getuser(), gethostname())) for feature in features: if not feature.has_to_run(world.config.scenarios): continue feature_element = self._get_element_from_model("feature", feature) description_element = etree.Element("description") description_element.text = etree.CDATA("\n".join( feature.description)) tags_element = etree.Element('tags') for tag in feature.tags: tag_element = etree.Element('tag') tag_element.text = tag.name tags_element.append(tag_element) scenarios_element = etree.Element("scenarios") for scenario in ( s for s in feature.all_scenarios if not isinstance(s, (ScenarioOutline, ScenarioLoop))): if not scenario.has_to_run(world.config.scenarios): continue scenario_element = self._get_element_from_model( "scenario", scenario) scenario_tags_element = etree.Element('tags') scenario_element.append(scenario_tags_element) for tag in scenario.tags: tag_element = etree.Element('tag') tag_element.text = tag.name if tag.arg: tag_element.text += '({0})'.format(tag.arg) scenario_tags_element.append(tag_element) for step in scenario.all_steps: step_element = self._get_element_from_model("step", step) if step.state is Step.State.FAILED: failure_element = etree.Element( "failure", type=step.failure.name, message=step.failure.reason) failure_element.text = etree.CDATA( self._strip_ansi(step.failure.traceback)) step_element.append(failure_element) scenario_element.append(step_element) scenarios_element.append(scenario_element) feature_element.append(description_element) feature_element.append(tags_element) feature_element.append(scenarios_element) testrun_element.append(feature_element) with open(world.config.bdd_xml, "w+") as f: content = etree.tostring(testrun_element, pretty_print=True, xml_declaration=True, encoding="utf-8") try: if not isinstance(content, str): content = content.decode("utf-8") except Exception: pass finally: f.write(content)
async def __aenter__(self): if self._connection: raise RadishError("Already connected to redis!") self._connection = await self._connection_factory() return self
def connection(self) -> Redis: if not self._connection: raise RadishError("Connection to redis has not been initialised.") return self._connection