# Path: ifcb/data/identifiers.py
# def timestamp2regex(pattern):
# def c(pattern):
# def m(pattern, string):
#     def col_or_scalar(o):
#     def nones(n):
# def parse(pid):
# def unparse(parsed):
#     def __init__(self, pid, parse=True):
#     def isvalid(self):
#     def copy(self):
#     def __cmp__(self, other):
#     def __eq__(self, other):
#     def parsed(self):
#     def __getattr__(self, name):
#     def with_target(self, target_number, namespace=True):
#     def timestamp(self):
#     def __setattr__(self, name, value):
#     def __repr__(self):
#     def __str__(self):
# V1_PID_PATTERN = '(IFCB1_(yyyy_DDD_HHMMSS))(any)'
# V2_PID_PATTERN = '(D(yyyymmddTHHMMSS)_IFCB111)(any)'
# class Pid(object):
# 
# Path: ifcb/data/identifiers.py
# class Pid(object):
#     """
#     Represents the permanent identifier of an IFCB bin.
#     Provides attribute-based access to the relevant parsed
#     fields of a PID. ``Pid``s sort by alpha.
#     """
#     def __init__(self, pid, parse=True):
#         """
#         Construct a Pid object from a string.
#         Parsing is optional in case it needs
#         to be deferred.
# 
#         :param pid: the pid
#         :param parse: whether to parse
#         """
#         self.pid = pid
#         self._parsed = None
#         if parse:
#             self.parsed
#     def isvalid(self):
#         """
#         Check this PID for validity.
#         """
#         try:
#             self.parsed # parse if not already
#             return True
#         except ValueError:
#             pass
#         return False
#     def copy(self):
#         new_pid = Pid(self.pid, parse=False)
#         if self._parsed is not None:
#             # avoid re-parsing
#             new_pid._parsed = self._parsed.copy()
#         return new_pid
#     def __cmp__(self, other):
#         try:
#             if self.pid < other.pid:
#                 return -1
#             elif self.pid > other.pid:
#                 return 1
#         except AttributeError:
#             if self.pid < other:
#                 return -1
#             elif self.pid > other:
#                 return 1
#         else:
#             return 0
#     def __eq__(self, other):
#         try:
#             return self.pid == other.pid
#         except AttributeError:
#             return self.pid == other
#     @property
#     def parsed(self):
#         """
#         The parsed PID
#         """
#         if self._parsed is None:
#             # convert some properties to int
#             p = parse(self.pid)
#             for ip in ['target', 'instrument', 'schema_version']:
#                 if p[ip] is not None:
#                     p[ip] = int(p[ip])
#             self._parsed = p
#         return self._parsed
#     def __getattr__(self, name):
#         if name in ['pid','_parsed','parsed']:
#             raise AttributeError
#         try:
#             return self.parsed[name]
#         except KeyError:
#             raise AttributeError
#     def with_target(self, target_number, namespace=True):
#         """
#         Add a target number to the pid's bin_lid. Does not
#         include product or extension. Optionally includes
#         namespace prefix. This is more efficient than the
#         following approach, which will preserve product
#         and extension:
# 
#         >>> my_pid = Pid('IFCB1_2000_001_123456_blob')
#         >>> new_pid = my_pid.copy()
#         >>> new_pid.target = 927
#         >>> new_pid
#         <pid IFCB1_2000_001_123456_00927_blob>
# 
#         :param target_number: the target number
#         :type target_number: int
#         :param namespace: whether to include the namespace prefix
#         :type namespace: bool
#         :returns: the target ID (as a string)
#         """
#         ns = ''
#         if namespace and self.namespace is not None:
#             ns = self.namespace
#         return ns + self.bin_lid + '_%05d' % target_number
#     @property
#     def timestamp(self):
#         """
#         The timestamp of the bin as a ``datetime``
#         """
#         return pd.to_datetime(self.parsed['timestamp'], format=self.parsed['timestamp_format'], utc=True)
#     def __setattr__(self, name, value):
#         if name == 'target':
#             self.parsed # ensure parsing is complete
#             self._parsed.update({ name: int(value) })
#             self.pid = unparse(self._parsed)
#         elif name in ['product', 'extension']:
#             self.parsed # ensure parsing is complete
#             self._parsed.update({ name: value })
#             self.pid = unparse(self._parsed)
#         else:
#             super(Pid, self).__setattr__(name, value)
#     def __repr__(self):
#         return '<pid %s>' % self.pid
#     def __str__(self):
#         return self.pid


import unittest
import random
from ifcb.data import identifiers as ids
from ifcb.data.identifiers import Pid
            assert Pid(spid) == spid
    def test_ne(self):
        for spid in GOOD:
            diff = spid + '.foo'
            assert Pid(spid) != Pid(diff)
            assert Pid(spid) != diff
    def test_copy_unparsed(self):
        for spid in GOOD:
            # create invalid, unparsed pid
            pid = Pid('_' + spid, parse=False)
            # copy it
            copy = pid.copy()
            # now parse it, expecting ValueError
            with self.assertRaises(ValueError):
                copy.parsed
    def test_copy(self):
        for spid in GOOD:
            pid = Pid(spid)
            copy = pid.copy()
            assert pid == copy

class TestV1Identifiers(unittest.TestCase):
    def test_timestamp_validation(self):
        with self.assertRaises(ValueError):
            ids.parse('IFCB1_2000_999_000000')
        with self.assertRaises(ValueError):
            ids.parse('IFCB1_2000_001_990000')
        with self.assertRaises(ValueError):
            ids.parse('IFCB1_2000_001_009900')
        with self.assertRaises(ValueError):

# Path: ifcb/data/identifiers.py
# def timestamp2regex(pattern):
# def c(pattern):
# def m(pattern, string):
#     def col_or_scalar(o):
#     def nones(n):
# def parse(pid):
# def unparse(parsed):
#     def __init__(self, pid, parse=True):
#     def isvalid(self):
#     def copy(self):
#     def __cmp__(self, other):
#     def __eq__(self, other):
#     def parsed(self):
#     def __getattr__(self, name):
#     def with_target(self, target_number, namespace=True):
#     def timestamp(self):
#     def __setattr__(self, name, value):
#     def __repr__(self):
#     def __str__(self):
# V1_PID_PATTERN = '(IFCB1_(yyyy_DDD_HHMMSS))(any)'
# V2_PID_PATTERN = '(D(yyyymmddTHHMMSS)_IFCB111)(any)'
# class Pid(object):
# 
# Path: ifcb/data/identifiers.py
# class Pid(object):
#     """
#     Represents the permanent identifier of an IFCB bin.
#     Provides attribute-based access to the relevant parsed
#     fields of a PID. ``Pid``s sort by alpha.
#     """
#     def __init__(self, pid, parse=True):
#         """
#         Construct a Pid object from a string.
#         Parsing is optional in case it needs
#         to be deferred.
# 
#         :param pid: the pid
#         :param parse: whether to parse
#         """
#         self.pid = pid
#         self._parsed = None
#         if parse:
#             self.parsed
#     def isvalid(self):
#         """
#         Check this PID for validity.
#         """
#         try:
#             self.parsed # parse if not already
#             return True
#         except ValueError:
#             pass
#         return False
#     def copy(self):
#         new_pid = Pid(self.pid, parse=False)
#         if self._parsed is not None:
#             # avoid re-parsing
#             new_pid._parsed = self._parsed.copy()
#         return new_pid
#     def __cmp__(self, other):
#         try:
#             if self.pid < other.pid:
#                 return -1
#             elif self.pid > other.pid:
#                 return 1
#         except AttributeError:
#             if self.pid < other:
#                 return -1
#             elif self.pid > other:
#                 return 1
#         else:
#             return 0
#     def __eq__(self, other):
#         try:
#             return self.pid == other.pid
#         except AttributeError:
#             return self.pid == other
#     @property
#     def parsed(self):
#         """
#         The parsed PID
#         """
#         if self._parsed is None:
#             # convert some properties to int
#             p = parse(self.pid)
#             for ip in ['target', 'instrument', 'schema_version']:
#                 if p[ip] is not None:
#                     p[ip] = int(p[ip])
#             self._parsed = p
#         return self._parsed
#     def __getattr__(self, name):
#         if name in ['pid','_parsed','parsed']:
#             raise AttributeError
#         try:
#             return self.parsed[name]
#         except KeyError:
#             raise AttributeError
#     def with_target(self, target_number, namespace=True):
#         """
#         Add a target number to the pid's bin_lid. Does not
#         include product or extension. Optionally includes
#         namespace prefix. This is more efficient than the
#         following approach, which will preserve product
#         and extension:
# 
#         >>> my_pid = Pid('IFCB1_2000_001_123456_blob')
#         >>> new_pid = my_pid.copy()
#         >>> new_pid.target = 927
#         >>> new_pid
#         <pid IFCB1_2000_001_123456_00927_blob>
# 
#         :param target_number: the target number
#         :type target_number: int
#         :param namespace: whether to include the namespace prefix
#         :type namespace: bool
#         :returns: the target ID (as a string)
#         """
#         ns = ''
#         if namespace and self.namespace is not None:
#             ns = self.namespace
#         return ns + self.bin_lid + '_%05d' % target_number
#     @property
#     def timestamp(self):
#         """
#         The timestamp of the bin as a ``datetime``
#         """
#         return pd.to_datetime(self.parsed['timestamp'], format=self.parsed['timestamp_format'], utc=True)
#     def __setattr__(self, name, value):
#         if name == 'target':
#             self.parsed # ensure parsing is complete
#             self._parsed.update({ name: int(value) })
#             self.pid = unparse(self._parsed)
#         elif name in ['product', 'extension']:
#             self.parsed # ensure parsing is complete
#             self._parsed.update({ name: value })
#             self.pid = unparse(self._parsed)
#         else:
#             super(Pid, self).__setattr__(name, value)
#     def __repr__(self):
#         return '<pid %s>' % self.pid
#     def __str__(self):
#         return self.pid


# Path: ifcb/tests/data/test_identifiers.py
import unittest
import random
from ifcb.data import identifiers as ids
from ifcb.data.identifiers import Pid

            assert Pid(spid) == spid
    def test_ne(self):
        for spid in GOOD:
            diff = spid + '.foo'
            assert Pid(spid) != Pid(diff)
            assert Pid(spid) != diff
    def test_copy_unparsed(self):
        for spid in GOOD:
            # create invalid, unparsed pid
            pid = Pid('_' + spid, parse=False)
            # copy it
            copy = pid.copy()
            # now parse it, expecting ValueError
            with self.assertRaises(ValueError):
                copy.parsed
    def test_copy(self):
        for spid in GOOD:
            pid = Pid(spid)
            copy = pid.copy()
            assert pid == copy

class TestV1Identifiers(unittest.TestCase):
    def test_timestamp_validation(self):
        with self.assertRaises(ValueError):
            ids.parse('IFCB1_2000_999_000000')
        with self.assertRaises(ValueError):
            ids.parse('IFCB1_2000_001_990000')
        with self.assertRaises(ValueError):
            ids.parse('IFCB1_2000_001_009900')
        with self.assertRaises(ValueError):

            ids.parse('IFCB1_2000_001_000099')