def setUp(self): super(TestTemplatePath, self).setUp() # Make various types of keys(fields) self.keys = { "Sequence": StringKey("Sequence"), "Shot": StringKey("Shot", default="s1", choices=["s1", "s2", "shot_1"]), "Step": StringKey("Step"), "branch": StringKey("branch", filter_by="alphanumeric"), "name": StringKey("name"), "version": IntegerKey("version", format_spec="03"), "snapshot": IntegerKey("snapshot", format_spec="03"), "ext": StringKey("ext"), "seq_num": SequenceKey("seq_num"), "frame": SequenceKey("frame", format_spec="04") } # Make a template self.definition = "shots/{Sequence}/{Shot}/{Step}/work/{Shot}.{branch}.v{version}.{snapshot}.ma" self.template_path = TemplatePath(self.definition, self.keys, self.project_root) # make template with sequence key self.sequence = TemplatePath("/path/to/seq.{frame}.ext", self.keys, "", "frame")
def setUp(self): super(TestTemplate, self).setUp() # Make various types of keys(fields) self.keys = { "Sequence": StringKey("Sequence"), "Shot": StringKey("Shot", default="s1", choices=["s1", "s2", "shot_1"]), "Step": StringKey("Step"), "branch": StringKey("branch", filter_by="alphanumeric"), "name": StringKey("name"), "version": IntegerKey("version", format_spec="03"), "snapshot": IntegerKey("snapshot", format_spec="03"), "ext": StringKey("ext"), "seq_num": SequenceKey("seq_num"), "frame": SequenceKey("frame", format_spec="04"), "day_month_year": TimestampKey("day_month_year", format_spec="%d_%m_%Y") } # Make a template self.definition = "shots/{Sequence}/{Shot}/{Step}/work/{Shot}.{branch}.v{version}.{snapshot}.{day_month_year}.ma" self.template = Template(self.definition, self.keys)
def setUp(self): super(TestTemplatePath, self).setUp( parameters={"primary_root_name": "primary_with_a_different_name"}) # Make various types of keys(fields) self.keys = { "Sequence": StringKey("Sequence"), "Shot": StringKey("Shot", default="s1", choices=["s1", "s2", "shot_1"]), "Step": StringKey("Step"), "branch": StringKey("branch", filter_by="alphanumeric"), "name": StringKey("name"), "name_alpha": StringKey("name_alpha", filter_by="alphanumeric"), "version": IntegerKey("version", format_spec="03"), "snapshot": IntegerKey("snapshot", format_spec="03"), "ext": StringKey("ext"), "seq_num": SequenceKey("seq_num"), "frame": SequenceKey("frame", format_spec="04"), } # Make a template self.definition = "shots/{Sequence}/{Shot}/{Step}/work/{Shot}.{branch}.v{version}.{snapshot}.ma" # legacy style template object which only knows about the currently running operating system self.template_path_current_os_only = TemplatePath( self.definition, self.keys, self.project_root) project_root = os.path.join(self.tank_temp, "project_code") self._project_roots = {self.primary_root_name: {}} # Create the roots.yml like structure. Double down on the key names so it can be used in all scenarios # where we require the roots. for os_name in [ "windows_path", "linux_path", "mac_path", "win32", "linux2", "darwin", ]: self._project_roots[self.primary_root_name][os_name] = project_root self._primary_project_root = project_root # new style template object which supports all recognized platforms # get all OS roots for primary storage all_roots = self._project_roots[self.primary_root_name] self.template_path = TemplatePath(self.definition, self.keys, self.project_root, per_platform_roots=all_roots) self.project_root_template = TemplatePath("/", self.keys, self.project_root, per_platform_roots=all_roots) # make template with sequence key self.sequence = TemplatePath("/path/to/seq.{frame}.ext", self.keys, "", "frame")
def _test_non_strict_matching(self, padding_char): """ Allows to test strict matching with a specific padding character. :param padding_char: Character to test padding with. Should be space or 0. """ key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=False) # The padding char is missing in the format specifier, but we still need when validating # results. if padding_char == '': padding_char = ' ' # It should match because they are valid numbers. self.assertEqual(key.value_from_str("000"), 0) self.assertEqual(key.value_from_str("0"), 0) self.assertEqual(key.value_from_str("0"), 0) # While the number doesn't make any sense as far as formatting is concerned, this used # to work in old versions of Toolkit and needs to keep working in non strict mode. self.assertEqual(key.value_from_str("%s000" % padding_char), 0) # It should match a template with too many digits... self.assertEqual(key.value_from_str("20000"), 20000) # ... even if they are all zeros because lossy matching. self.assertEqual(key.value_from_str("00000"), 0) # From path to tokens back to path should be lossy. value = key.value_from_str("1") self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value)) self._test_nan(key, "expected an Integer")
def test_ambiguous_wrong_type(self): keys = { "some_num": IntegerKey("some_num"), "other_num": IntegerKey("other_num") } self.keys.update(keys) definition = "build/{Asset}_{some_num}_{other_num}.{ext}" input_path = "build/cat_1_man_14_2.jpeg" expected = { "Asset": "cat_1_man", "some_num": 14, "other_num": 2, "ext": "jpeg" } self.assert_path_matches(definition, input_path, expected)
def setUp(self): super(TestPathsFromTemplateGlob, self).setUp() keys = {"Shot": StringKey("Shot"), "version": IntegerKey("version", format_spec="03"), "seq_num": SequenceKey("seq_num", format_spec="05")} self.template = TemplatePath("{Shot}/{version}/filename.{seq_num}", keys, root_path=self.project_root)
def test_skip_invalid(self): """Test that files not valid for an template are not returned. This refers to bug reported in Ticket #17090 """ keys = { "Shot": StringKey("Shot"), "Sequence": StringKey("Sequence"), "Step": StringKey("Step"), "name": StringKey("name"), "version": IntegerKey("version", format_spec="03") } definition = "sequences/{Sequence}/{Shot}/{Step}/work/{name}.v{version}.nk" template = TemplatePath(definition, keys, self.project_root, "my_template") tk = tank.Tank(self.project_root) tk._templates = {template.name: template} bad_file_path = os.path.join(self.project_root, "sequences", "Sequence1", "Shot1", "Foot", "work", "name1.va.nk") good_file_path = os.path.join(self.project_root, "sequences", "Sequence1", "Shot1", "Foot", "work", "name.v001.nk") self.create_file(bad_file_path) self.create_file(good_file_path) ctx_fields = {"Sequence": "Sequence1", "Shot": "Shot1", "Step": "Foot"} result = tk.paths_from_template(template, ctx_fields) self.assertIn(good_file_path, result) self.assertNotIn(bad_file_path, result)
def test_template_query_invalid(self): """ Check case that value returned from shotgun is invalid. """ query_key = IntegerKey("shot_seq", shotgun_entity_type="Shot", shotgun_field_name="sg_sequence") self.keys["shot_seq"] = query_key template_def = "/sequence/{Sequence}/{Shot}/{Step}/work/{shot_seq}.ext" template = TemplatePath(template_def, self.keys, self.project_root) self.assertRaises(TankError, self.ctx.as_template_fields, template)
def test_aliased_key(self): key = IntegerKey("aliased_name") keys = {"initial_name": key} definition = "{initial_name}" template = TemplatePath(definition, keys, self.project_root) input_path = os.path.join(self.project_root, "3") expected = {"aliased_name": 3} result = template.get_fields(input_path) self.assertEquals(expected, result)
def setUp(self): super(TestTemplateString, self).setUp() self.keys = { "Sequence": StringKey("Sequence"), "Shot": StringKey("Shot"), "version": IntegerKey("version"), } self.template_string = TemplateString("something-{Shot}.{Sequence}", self.keys)
def setUp(self): super(TestTemplatePath, self).setUp() # Make various types of keys(fields) self.keys = { "Sequence": StringKey("Sequence"), "Shot": StringKey("Shot", default="s1", choices=["s1", "s2", "shot_1"]), "Step": StringKey("Step"), "branch": StringKey("branch", filter_by="alphanumeric"), "name": StringKey("name"), "name_alpha": StringKey("name_alpha", filter_by="alphanumeric"), "version": IntegerKey("version", format_spec="03"), "snapshot": IntegerKey("snapshot", format_spec="03"), "ext": StringKey("ext"), "seq_num": SequenceKey("seq_num"), "frame": SequenceKey("frame", format_spec="04") } # Make a template self.definition = "shots/{Sequence}/{Shot}/{Step}/work/{Shot}.{branch}.v{version}.{snapshot}.ma" # legacy style template object which only knows about the currently running operating system self.template_path_current_os_only = TemplatePath( self.definition, self.keys, self.project_root) # new style template object which supports all recognized platforms # get all OS roots for primary storage all_roots = self.pipeline_configuration.get_all_platform_data_roots( )["primary"] self.template_path = TemplatePath(self.definition, self.keys, self.project_root, per_platform_roots=all_roots) self.project_root_template = TemplatePath("/", self.keys, self.project_root, per_platform_roots=all_roots) # make template with sequence key self.sequence = TemplatePath("/path/to/seq.{frame}.ext", self.keys, "", "frame")
def test_double_int_key(self): """Test case that key of type int appears twice in definition.""" int_key = IntegerKey("int_key") definition = "{int_key}/something/{int_key}.else" template = TemplatePath(definition, {"int_key": int_key}, root_path=self.project_root) expected = {"int_key": 4} relative_path = "4/something/4.else" input_path = os.path.join(self.project_root, relative_path) actual = template.get_fields(input_path) self.assertEquals(expected, actual)
def test_aliased_key(self): """ Apply values to a template which has an aliased key. """ key = IntegerKey("aliased_name") keys = {"initial_name": key} definition = "{initial_name}" template = TemplatePath(definition, keys, self.project_root) expected = os.path.join(self.project_root, "2") fields = {"aliased_name": 2} self.assertEquals(expected, template.apply_fields(fields)) fields = {"initial_name": 2} self.assertRaises(TankError, template.apply_fields, fields)
class TestIntegerKey(ShotgunTestBase): def setUp(self): super(TestIntegerKey, self).setUp() self.int_field = IntegerKey("field_name") def test_bad_default(self): """Case that specified default does not match type.""" default_value = "default_value" self.assertRaises(TankError, IntegerKey, "field_name", default=default_value) def test_illegal_choice(self): """Choice conflict with type.""" choices_value = ["a", "b"] self.assertRaises(TankError, IntegerKey, "field_name", choices=choices_value) def test_format_set(self): format_spec = "03" template_field = IntegerKey("field_name", format_spec=format_spec) self.assertEqual(format_spec, template_field.format_spec) def test_validate_string_good(self): value = "23" self.assertTrue(self.int_field.validate(value)) def test_validate_int_good(self): value = 23 self.assertTrue(self.int_field.validate(value)) def test_validate_bad(self): value = "a" self.assertFalse(self.int_field.validate(value)) def test_str_from_value_good(self): value = 3 expected = "%s" % value result = self.int_field.str_from_value(value) self.assertEqual(expected, result) def test_str_from_value_zero(self): value = 0 expected = "%d" % value result = self.int_field.str_from_value(value) self.assertEqual(expected, result) def test_str_from_value_bad(self): value = "a" expected = "%s Illegal value '%s', expected an Integer" % (str(self.int_field), value) self.check_error_message(TankError, expected, self.int_field.str_from_value, value) def test_str_from_value_formatted(self): formatted_field = IntegerKey("field_name", format_spec="03") value = 3 expected = "%03d" % value result = formatted_field.str_from_value(value) self.assertEqual(expected, result) def test_str_from_value_ignore_type(self): value = "a" expected = value result = self.int_field.str_from_value(value, ignore_type=True) self.assertEqual(expected, result) def test_value_from_str(self): str_value = "32" self.assertEqual(32, self.int_field.value_from_str(str_value)) def test_repr(self): expected = "<Sgtk IntegerKey field_name>" self.assertEqual(expected, str(self.int_field)) def test_init_validation(self): """ Makes sure that parameter validation is correct in the constructor. """ # This should obviously work self._validate_key( IntegerKey("version_number"), strict_matching=None, format_spec=None ) # When specifying parameters, they should be set accordingly. self._validate_key( IntegerKey("version_number", format_spec="03", strict_matching=True), strict_matching=True, format_spec="03" ) self._validate_key( IntegerKey("version_number", format_spec="03", strict_matching=False), strict_matching=False, format_spec="03" ) self._validate_key( IntegerKey("version_number", format_spec="3", strict_matching=False), strict_matching=False, format_spec="3" ) # When specifying a format but not specifying the strict_matching, it should # still have strict_matching. self._validate_key( IntegerKey("version_number", format_spec="03"), strict_matching=True, format_spec="03" ) # Make sure than an error is raised when wrong types are passed in. with self.assertRaisesRegex(TankError, "is not of type boolean"): IntegerKey("version_number", strict_matching=1) with self.assertRaisesRegex(TankError, "is not of type string"): IntegerKey("version_number", format_spec=1) # Make sure that if the user specifies strict_matching with no format # there is an error error_regexp = "strict_matching can't be set" with self.assertRaisesRegex(TankError, error_regexp): IntegerKey("version_number", strict_matching=False) with self.assertRaisesRegex(TankError, error_regexp): IntegerKey("version_number", strict_matching=True) # We support 4 format_spec values: # - None # - non zero positive number # - zero followed by a non zero positive number IntegerKey("version_number", format_spec=None) IntegerKey("version_number", format_spec="1") IntegerKey("version_number", format_spec="01") # Make sure invalid formats are caught with self.assertRaisesRegex(TankError, "format_spec can't be empty"): IntegerKey("version_number", format_spec="") error_regexp = "has to either be" # We don't support the sign option. with self.assertRaisesRegex(TankError, error_regexp): IntegerKey("version_number", format_spec=" 3", strict_matching=False) with self.assertRaisesRegex(TankError, error_regexp): # Should throw because the padding number is not non zero. IntegerKey("version_number", format_spec="00") with self.assertRaisesRegex(TankError, error_regexp): # Should throw because it is not a non zero positive integer IntegerKey("version_number", format_spec="0") with self.assertRaisesRegex(TankError, error_regexp): # Should throw because the padding caracter is invalid IntegerKey("version_number", format_spec="a0") with self.assertRaisesRegex(TankError, error_regexp): # Should throw because the padding size is not a number. IntegerKey("version_number", format_spec="0a") def test_no_format_spec(self): key = IntegerKey("version_number") key.value_from_str def _validate_key(self, key, strict_matching, format_spec): """ Makes sure that an integer key's formatting options are correctly set. """ self.assertEqual(key.strict_matching, strict_matching) self.assertEqual(key.format_spec, format_spec) def test_non_strict_matching(self): """ In non strict mode, tokens can actually have less numbers than the padding requests. Also, if there are more, can also match. """ self._test_non_strict_matching('0') self._test_non_strict_matching('') def _test_non_strict_matching(self, padding_char): """ Allows to test strict matching with a specific padding character. :param padding_char: Character to test padding with. Should be space or 0. """ key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=False) # The padding char is missing in the format specifier, but we still need when validating # results. if padding_char == '': padding_char = ' ' # It should match because they are valid numbers. self.assertEqual(key.value_from_str("000"), 0) self.assertEqual(key.value_from_str("0"), 0) self.assertEqual(key.value_from_str("0"), 0) # While the number doesn't make any sense as far as formatting is concerned, this used # to work in old versions of Toolkit and needs to keep working in non strict mode. self.assertEqual(key.value_from_str("%s000" % padding_char), 0) # It should match a template with too many digits... self.assertEqual(key.value_from_str("20000"), 20000) # ... even if they are all zeros because lossy matching. self.assertEqual(key.value_from_str("00000"), 0) # From path to tokens back to path should be lossy. value = key.value_from_str("1") self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value)) self._test_nan(key, "expected an Integer") def _test_nan(self, key, error_msg): """ Tests a key with against values that are not numbers. :param key: Key to test. :param error_msg: Text that partially matches the error message. """ # Should fail because not a number with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("aaaa") with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("0a") with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("a0") with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("aa") def _test_strict_matching(self, padding_char): """ Allows to test strict matching with any padding type. """ # have a template that formats with two digits of padding. key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=True) self.assertTrue(key.strict_matching) # The padding char is missing in the format specifier, but we still need when validating # results. if padding_char == '': padding_char = ' ' # From path to tokens back to path should get back the same string when the expected number of # digits are found. value = key.value_from_str("%s%s1" % (padding_char, padding_char)) self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value)) # It should match a template with more digits. value = key.value_from_str("20000") self.assertEqual("20000", key.str_from_value(value)) key.value_from_str("123") error_msg = "does not match format spec" # It should not match a string with too few digits with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("1") # It should not match a template with too many digits that are all zero because that would # lossy. (there are more zeros than the format spec can rebuild) with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("0000") # It should not match negative numbers either with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("-1000") # It should not match baddly padded numbers with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("0100") # It should not match negative values with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("-01") self._test_nan(key, error_msg) def test_strict_matching(self): """ In strict mode, tokens have to have as much padding as the format specifier suggests. Less will not match. """ self._test_strict_matching('') self._test_strict_matching('0')
def test_str_from_value_formatted(self): formatted_field = IntegerKey("field_name", format_spec="03") value = 3 expected = "%03d" % value result = formatted_field.str_from_value(value) self.assertEquals(expected, result)
def test_format_set(self): format_spec = "03" template_field = IntegerKey("field_name", format_spec=format_spec) self.assertEquals(format_spec, template_field.format_spec)
def setUp(self): super(TestIntegerKey, self).setUp() self.int_field = IntegerKey("field_name")
class TestIntegerKey(TankTestBase): def setUp(self): super(TestIntegerKey, self).setUp() self.int_field = IntegerKey("field_name") def test_bad_default(self): """Case that specified default does not match type.""" default_value = "default_value" self.assertRaises(TankError, IntegerKey, "field_name", default=default_value) def test_illegal_choice(self): """Choice conflict with type.""" choices_value = ["a", "b"] self.assertRaises(TankError, IntegerKey, "field_name", choices=choices_value) def test_format_set(self): format_spec = "03" template_field = IntegerKey("field_name", format_spec=format_spec) self.assertEquals(format_spec, template_field.format_spec) def test_validate_string_good(self): value = "23" self.assertTrue(self.int_field.validate(value)) def test_validate_int_good(self): value = 23 self.assertTrue(self.int_field.validate(value)) def test_validate_bad(self): value = "a" self.assertFalse(self.int_field.validate(value)) def test_str_from_value_good(self): value = 3 expected = "%s" % value result = self.int_field.str_from_value(value) self.assertEquals(expected, result) def test_str_from_value_zero(self): value = 0 expected = "%d" % value result = self.int_field.str_from_value(value) self.assertEquals(expected, result) def test_str_from_value_bad(self): value = "a" expected = "%s Illegal value %s, expected an Integer" % (str( self.int_field), value) self.check_error_message(TankError, expected, self.int_field.str_from_value, value) def test_str_from_value_formatted(self): formatted_field = IntegerKey("field_name", format_spec="03") value = 3 expected = "%03d" % value result = formatted_field.str_from_value(value) self.assertEquals(expected, result) def test_str_from_value_ignore_type(self): value = "a" expected = value result = self.int_field.str_from_value(value, ignore_type=True) self.assertEquals(expected, result) def test_value_from_str(self): str_value = "32" self.assertEquals(32, self.int_field.value_from_str(str_value)) def test_repr(self): expected = "<Sgtk IntegerKey field_name>" self.assertEquals(expected, str(self.int_field))
class TestIntegerKey(TankTestBase): def setUp(self): super(TestIntegerKey, self).setUp() self.int_field = IntegerKey("field_name") def test_bad_default(self): """Case that specified default does not match type.""" default_value = "default_value" self.assertRaises(TankError, IntegerKey, "field_name", default=default_value) def test_illegal_choice(self): """Choice conflict with type.""" choices_value = ["a", "b"] self.assertRaises(TankError, IntegerKey, "field_name", choices=choices_value) def test_format_set(self): format_spec = "03" template_field = IntegerKey("field_name", format_spec=format_spec) self.assertEquals(format_spec, template_field.format_spec) def test_validate_string_good(self): value = "23" self.assertTrue(self.int_field.validate(value)) def test_validate_int_good(self): value = 23 self.assertTrue(self.int_field.validate(value)) def test_validate_bad(self): value = "a" self.assertFalse(self.int_field.validate(value)) def test_str_from_value_good(self): value = 3 expected = "%s" % value result = self.int_field.str_from_value(value) self.assertEquals(expected, result) def test_str_from_value_zero(self): value = 0 expected = "%d" % value result = self.int_field.str_from_value(value) self.assertEquals(expected, result) def test_str_from_value_bad(self): value = "a" expected = "%s Illegal value %s, expected an Integer" % (str(self.int_field), value) self.check_error_message(TankError, expected, self.int_field.str_from_value, value) def test_str_from_value_formatted(self): formatted_field = IntegerKey("field_name", format_spec="03") value = 3 expected = "%03d" % value result = formatted_field.str_from_value(value) self.assertEquals(expected, result) def test_str_from_value_ignore_type(self): value = "a" expected = value result = self.int_field.str_from_value(value, ignore_type=True) self.assertEquals(expected, result) def test_value_from_str(self): str_value = "32" self.assertEquals(32, self.int_field.value_from_str(str_value)) def test_repr(self): expected = "<Sgtk IntegerKey field_name>" self.assertEquals(expected, str(self.int_field))
def _test_strict_matching(self, padding_char): """ Allows to test strict matching with any padding type. """ # have a template that formats with two digits of padding. key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=True) self.assertTrue(key.strict_matching) # The padding char is missing in the format specifier, but we still need when validating # results. if padding_char == "": padding_char = " " # From path to tokens back to path should get back the same string when the expected number of # digits are found. value = key.value_from_str("%s%s1" % (padding_char, padding_char)) self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value)) # It should match a template with more digits. value = key.value_from_str("20000") self.assertEqual("20000", key.str_from_value(value)) key.value_from_str("123") error_msg = "does not match format spec" # It should not match a string with too few digits with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("1") # It should not match a template with too many digits that are all zero because that would # lossy. (there are more zeros than the format spec can rebuild) with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("0000") # It should not match negative numbers either with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("-1000") # It should not match baddly padded numbers with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("0100") # It should not match negative values with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("-01") self._test_nan(key, error_msg)
def test_no_format_spec(self): key = IntegerKey("version_number") key.value_from_str
class TestIntegerKey(ShotgunTestBase): def setUp(self): super(TestIntegerKey, self).setUp() self.int_field = IntegerKey("field_name") def test_bad_default(self): """Case that specified default does not match type.""" default_value = "default_value" self.assertRaises(TankError, IntegerKey, "field_name", default=default_value) def test_illegal_choice(self): """Choice conflict with type.""" choices_value = ["a", "b"] self.assertRaises(TankError, IntegerKey, "field_name", choices=choices_value) def test_format_set(self): format_spec = "03" template_field = IntegerKey("field_name", format_spec=format_spec) self.assertEqual(format_spec, template_field.format_spec) def test_validate_string_good(self): value = "23" self.assertTrue(self.int_field.validate(value)) def test_validate_int_good(self): value = 23 self.assertTrue(self.int_field.validate(value)) def test_validate_bad(self): value = "a" self.assertFalse(self.int_field.validate(value)) def test_str_from_value_good(self): value = 3 expected = "%s" % value result = self.int_field.str_from_value(value) self.assertEqual(expected, result) def test_str_from_value_zero(self): value = 0 expected = "%d" % value result = self.int_field.str_from_value(value) self.assertEqual(expected, result) def test_str_from_value_bad(self): value = "a" expected = "%s Illegal value '%s', expected an Integer" % ( str(self.int_field), value, ) self.check_error_message(TankError, expected, self.int_field.str_from_value, value) def test_str_from_value_formatted(self): formatted_field = IntegerKey("field_name", format_spec="03") value = 3 expected = "%03d" % value result = formatted_field.str_from_value(value) self.assertEqual(expected, result) def test_str_from_value_ignore_type(self): value = "a" expected = value result = self.int_field.str_from_value(value, ignore_type=True) self.assertEqual(expected, result) def test_value_from_str(self): str_value = "32" self.assertEqual(32, self.int_field.value_from_str(str_value)) def test_repr(self): expected = "<Sgtk IntegerKey field_name>" self.assertEqual(expected, str(self.int_field)) def test_init_validation(self): """ Makes sure that parameter validation is correct in the constructor. """ # This should obviously work self._validate_key(IntegerKey("version_number"), strict_matching=None, format_spec=None) # When specifying parameters, they should be set accordingly. self._validate_key( IntegerKey("version_number", format_spec="03", strict_matching=True), strict_matching=True, format_spec="03", ) self._validate_key( IntegerKey("version_number", format_spec="03", strict_matching=False), strict_matching=False, format_spec="03", ) self._validate_key( IntegerKey("version_number", format_spec="3", strict_matching=False), strict_matching=False, format_spec="3", ) # When specifying a format but not specifying the strict_matching, it should # still have strict_matching. self._validate_key( IntegerKey("version_number", format_spec="03"), strict_matching=True, format_spec="03", ) # Make sure than an error is raised when wrong types are passed in. with self.assertRaisesRegex(TankError, "is not of type boolean"): IntegerKey("version_number", strict_matching=1) with self.assertRaisesRegex(TankError, "is not of type string"): IntegerKey("version_number", format_spec=1) # Make sure that if the user specifies strict_matching with no format # there is an error error_regexp = "strict_matching can't be set" with self.assertRaisesRegex(TankError, error_regexp): IntegerKey("version_number", strict_matching=False) with self.assertRaisesRegex(TankError, error_regexp): IntegerKey("version_number", strict_matching=True) # We support 4 format_spec values: # - None # - non zero positive number # - zero followed by a non zero positive number IntegerKey("version_number", format_spec=None) IntegerKey("version_number", format_spec="1") IntegerKey("version_number", format_spec="01") # Make sure invalid formats are caught with self.assertRaisesRegex(TankError, "format_spec can't be empty"): IntegerKey("version_number", format_spec="") error_regexp = "has to either be" # We don't support the sign option. with self.assertRaisesRegex(TankError, error_regexp): IntegerKey("version_number", format_spec=" 3", strict_matching=False) with self.assertRaisesRegex(TankError, error_regexp): # Should throw because the padding number is not non zero. IntegerKey("version_number", format_spec="00") with self.assertRaisesRegex(TankError, error_regexp): # Should throw because it is not a non zero positive integer IntegerKey("version_number", format_spec="0") with self.assertRaisesRegex(TankError, error_regexp): # Should throw because the padding caracter is invalid IntegerKey("version_number", format_spec="a0") with self.assertRaisesRegex(TankError, error_regexp): # Should throw because the padding size is not a number. IntegerKey("version_number", format_spec="0a") def test_no_format_spec(self): key = IntegerKey("version_number") key.value_from_str def _validate_key(self, key, strict_matching, format_spec): """ Makes sure that an integer key's formatting options are correctly set. """ self.assertEqual(key.strict_matching, strict_matching) self.assertEqual(key.format_spec, format_spec) def test_non_strict_matching(self): """ In non strict mode, tokens can actually have less numbers than the padding requests. Also, if there are more, can also match. """ self._test_non_strict_matching("0") self._test_non_strict_matching("") def _test_non_strict_matching(self, padding_char): """ Allows to test strict matching with a specific padding character. :param padding_char: Character to test padding with. Should be space or 0. """ key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=False) # The padding char is missing in the format specifier, but we still need when validating # results. if padding_char == "": padding_char = " " # It should match because they are valid numbers. self.assertEqual(key.value_from_str("000"), 0) self.assertEqual(key.value_from_str("0"), 0) self.assertEqual(key.value_from_str("0"), 0) # While the number doesn't make any sense as far as formatting is concerned, this used # to work in old versions of Toolkit and needs to keep working in non strict mode. self.assertEqual(key.value_from_str("%s000" % padding_char), 0) # It should match a template with too many digits... self.assertEqual(key.value_from_str("20000"), 20000) # ... even if they are all zeros because lossy matching. self.assertEqual(key.value_from_str("00000"), 0) # From path to tokens back to path should be lossy. value = key.value_from_str("1") self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value)) self._test_nan(key, "expected an Integer") def _test_nan(self, key, error_msg): """ Tests a key with against values that are not numbers. :param key: Key to test. :param error_msg: Text that partially matches the error message. """ # Should fail because not a number with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("aaaa") with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("0a") with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("a0") with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("aa") def _test_strict_matching(self, padding_char): """ Allows to test strict matching with any padding type. """ # have a template that formats with two digits of padding. key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=True) self.assertTrue(key.strict_matching) # The padding char is missing in the format specifier, but we still need when validating # results. if padding_char == "": padding_char = " " # From path to tokens back to path should get back the same string when the expected number of # digits are found. value = key.value_from_str("%s%s1" % (padding_char, padding_char)) self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value)) # It should match a template with more digits. value = key.value_from_str("20000") self.assertEqual("20000", key.str_from_value(value)) key.value_from_str("123") error_msg = "does not match format spec" # It should not match a string with too few digits with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("1") # It should not match a template with too many digits that are all zero because that would # lossy. (there are more zeros than the format spec can rebuild) with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("0000") # It should not match negative numbers either with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("-1000") # It should not match baddly padded numbers with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("0100") # It should not match negative values with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("-01") self._test_nan(key, error_msg) def test_strict_matching(self): """ In strict mode, tokens have to have as much padding as the format specifier suggests. Less will not match. """ self._test_strict_matching("") self._test_strict_matching("0")
def _test_strict_matching(self, padding_char): """ Allows to test strict matching with any padding type. """ # have a template that formats with two digits of padding. key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=True) self.assertTrue(key.strict_matching) # The padding char is missing in the format specifier, but we still need when validating # results. if padding_char == '': padding_char = ' ' # From path to tokens back to path should get back the same string when the expected number of # digits are found. value = key.value_from_str("%s%s1" % (padding_char, padding_char)) self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value)) # It should match a template with more digits. value = key.value_from_str("20000") self.assertEqual("20000", key.str_from_value(value)) key.value_from_str("123") error_msg = "does not match format spec" # It should not match a string with too few digits with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("1") # It should not match a template with too many digits that are all zero because that would # lossy. (there are more zeros than the format spec can rebuild) with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("0000") # It should not match negative numbers either with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("-1000") # It should not match baddly padded numbers with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("0100") # It should not match negative values with self.assertRaisesRegex(TankError, error_msg): key.value_from_str("-01") self._test_nan(key, error_msg)
def test_init_validation(self): """ Makes sure that parameter validation is correct in the constructor. """ # This should obviously work self._validate_key(IntegerKey("version_number"), strict_matching=None, format_spec=None) # When specifying parameters, they should be set accordingly. self._validate_key( IntegerKey("version_number", format_spec="03", strict_matching=True), strict_matching=True, format_spec="03", ) self._validate_key( IntegerKey("version_number", format_spec="03", strict_matching=False), strict_matching=False, format_spec="03", ) self._validate_key( IntegerKey("version_number", format_spec="3", strict_matching=False), strict_matching=False, format_spec="3", ) # When specifying a format but not specifying the strict_matching, it should # still have strict_matching. self._validate_key( IntegerKey("version_number", format_spec="03"), strict_matching=True, format_spec="03", ) # Make sure than an error is raised when wrong types are passed in. with self.assertRaisesRegex(TankError, "is not of type boolean"): IntegerKey("version_number", strict_matching=1) with self.assertRaisesRegex(TankError, "is not of type string"): IntegerKey("version_number", format_spec=1) # Make sure that if the user specifies strict_matching with no format # there is an error error_regexp = "strict_matching can't be set" with self.assertRaisesRegex(TankError, error_regexp): IntegerKey("version_number", strict_matching=False) with self.assertRaisesRegex(TankError, error_regexp): IntegerKey("version_number", strict_matching=True) # We support 4 format_spec values: # - None # - non zero positive number # - zero followed by a non zero positive number IntegerKey("version_number", format_spec=None) IntegerKey("version_number", format_spec="1") IntegerKey("version_number", format_spec="01") # Make sure invalid formats are caught with self.assertRaisesRegex(TankError, "format_spec can't be empty"): IntegerKey("version_number", format_spec="") error_regexp = "has to either be" # We don't support the sign option. with self.assertRaisesRegex(TankError, error_regexp): IntegerKey("version_number", format_spec=" 3", strict_matching=False) with self.assertRaisesRegex(TankError, error_regexp): # Should throw because the padding number is not non zero. IntegerKey("version_number", format_spec="00") with self.assertRaisesRegex(TankError, error_regexp): # Should throw because it is not a non zero positive integer IntegerKey("version_number", format_spec="0") with self.assertRaisesRegex(TankError, error_regexp): # Should throw because the padding caracter is invalid IntegerKey("version_number", format_spec="a0") with self.assertRaisesRegex(TankError, error_regexp): # Should throw because the padding size is not a number. IntegerKey("version_number", format_spec="0a")