tdcv2 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (610) hide show
  1. tdcv2/__init__.py +6 -0
  2. tdcv2/cli/__init__.py +5 -0
  3. tdcv2/cli/__main__.py +5 -0
  4. tdcv2/cli/args.py +149 -0
  5. tdcv2/cli/init.py +206 -0
  6. tdcv2/cli/main.py +299 -0
  7. tdcv2/cli/pack.py +276 -0
  8. tdcv2/cli/pack_picker.py +975 -0
  9. tdcv2/compute/__init__.py +6 -0
  10. tdcv2/compute/encode.py +59 -0
  11. tdcv2/compute/evaluate.py +384 -0
  12. tdcv2/compute/value.py +125 -0
  13. tdcv2/date/__init__.py +5 -0
  14. tdcv2/date/formatter.py +163 -0
  15. tdcv2/date/gen.py +225 -0
  16. tdcv2/date/locales.py +481 -0
  17. tdcv2/date/parse.py +83 -0
  18. tdcv2/date/plain.py +142 -0
  19. tdcv2/distribution/__init__.py +5 -0
  20. tdcv2/distribution/hamilton.py +78 -0
  21. tdcv2/distribution/percent_mask.py +98 -0
  22. tdcv2/engine/__init__.py +5 -0
  23. tdcv2/engine/_shard.py +47 -0
  24. tdcv2/engine/disk.py +32 -0
  25. tdcv2/engine/exact_uniq.py +326 -0
  26. tdcv2/engine/external_sort.py +89 -0
  27. tdcv2/engine/memory.py +1739 -0
  28. tdcv2/engine/parallel.py +138 -0
  29. tdcv2/engine/per_row.py +323 -0
  30. tdcv2/engine/repeat_keyed.py +158 -0
  31. tdcv2/engine/router.py +202 -0
  32. tdcv2/engine/stream.py +1406 -0
  33. tdcv2/errors/__init__.py +14 -0
  34. tdcv2/errors/diagnostic.py +95 -0
  35. tdcv2/errors/render.py +200 -0
  36. tdcv2/expr/__init__.py +6 -0
  37. tdcv2/expr/evaluate.py +205 -0
  38. tdcv2/expr/parse.py +295 -0
  39. tdcv2/format/__init__.py +5 -0
  40. tdcv2/format/interpolate.py +136 -0
  41. tdcv2/format/mask.py +202 -0
  42. tdcv2/format/transforms.py +226 -0
  43. tdcv2/formatter/__init__.py +5 -0
  44. tdcv2/formatter/format.py +301 -0
  45. tdcv2/generators/__init__.py +25 -0
  46. tdcv2/generators/accumulate.py +163 -0
  47. tdcv2/generators/advanced_regex.py +596 -0
  48. tdcv2/generators/counter.py +19 -0
  49. tdcv2/generators/file.py +423 -0
  50. tdcv2/generators/http.py +208 -0
  51. tdcv2/generators/imperfections.py +133 -0
  52. tdcv2/generators/number.py +409 -0
  53. tdcv2/generators/regex.py +485 -0
  54. tdcv2/generators/repeat.py +203 -0
  55. tdcv2/generators/symbol.py +82 -0
  56. tdcv2/lib/__init__.py +5 -0
  57. tdcv2/lib/numbers.py +74 -0
  58. tdcv2/lib/text.py +31 -0
  59. tdcv2/model/__init__.py +33 -0
  60. tdcv2/model/config.py +272 -0
  61. tdcv2/output/__init__.py +5 -0
  62. tdcv2/output/column_type.py +153 -0
  63. tdcv2/output/columns.py +219 -0
  64. tdcv2/output/parquet/__init__.py +27 -0
  65. tdcv2/output/parquet/convert.py +244 -0
  66. tdcv2/output/parquet/dictionary.py +66 -0
  67. tdcv2/output/parquet/list_levels.py +75 -0
  68. tdcv2/output/parquet/plain.py +124 -0
  69. tdcv2/output/parquet/rle.py +108 -0
  70. tdcv2/output/parquet/schema.py +131 -0
  71. tdcv2/output/parquet/snappy.py +129 -0
  72. tdcv2/output/parquet/statistics.py +124 -0
  73. tdcv2/output/parquet/thrift.py +136 -0
  74. tdcv2/output/parquet/writer.py +522 -0
  75. tdcv2/output/parquet_output.py +134 -0
  76. tdcv2/packs/__init__.py +17 -0
  77. tdcv2/packs/data_packs.py +274 -0
  78. tdcv2/packs/project_config.py +222 -0
  79. tdcv2/packs/registry.py +246 -0
  80. tdcv2/packs/source.py +190 -0
  81. tdcv2/packs_data/common/book/isbn10.txt +25 -0
  82. tdcv2/packs_data/common/book/isbn13.txt +31 -0
  83. tdcv2/packs_data/common/database/collation.txt +10 -0
  84. tdcv2/packs_data/common/database/column.txt +28 -0
  85. tdcv2/packs_data/common/database/engine.txt +10 -0
  86. tdcv2/packs_data/common/database/type.txt +21 -0
  87. tdcv2/packs_data/common/dev/browser.txt +12 -0
  88. tdcv2/packs_data/common/dev/environment.txt +12 -0
  89. tdcv2/packs_data/common/dev/framework.txt +31 -0
  90. tdcv2/packs_data/common/dev/frameworkByLanguage/C#.txt +7 -0
  91. tdcv2/packs_data/common/dev/frameworkByLanguage/Go.txt +7 -0
  92. tdcv2/packs_data/common/dev/frameworkByLanguage/Java.txt +8 -0
  93. tdcv2/packs_data/common/dev/frameworkByLanguage/JavaScript.txt +10 -0
  94. tdcv2/packs_data/common/dev/frameworkByLanguage/PHP.txt +7 -0
  95. tdcv2/packs_data/common/dev/frameworkByLanguage/Python.txt +10 -0
  96. tdcv2/packs_data/common/dev/frameworkByLanguage/Ruby.txt +6 -0
  97. tdcv2/packs_data/common/dev/frameworkByLanguage/Rust.txt +7 -0
  98. tdcv2/packs_data/common/dev/frameworkByLanguage/Swift.txt +6 -0
  99. tdcv2/packs_data/common/dev/frameworkByLanguage/TypeScript.txt +8 -0
  100. tdcv2/packs_data/common/dev/httpHeader.txt +22 -0
  101. tdcv2/packs_data/common/dev/languageCoherent.txt +13 -0
  102. tdcv2/packs_data/common/dev/logLevel.txt +9 -0
  103. tdcv2/packs_data/common/dev/os.txt +19 -0
  104. tdcv2/packs_data/common/dev/programmingLanguage.txt +37 -0
  105. tdcv2/packs_data/common/dev/spdxLicense.txt +18 -0
  106. tdcv2/packs_data/common/device/iccid.txt +36 -0
  107. tdcv2/packs_data/common/device/imei.txt +36 -0
  108. tdcv2/packs_data/common/docs/mrz/id_td1.txt +93 -0
  109. tdcv2/packs_data/common/docs/mrz/passport_td3.txt +105 -0
  110. tdcv2/packs_data/common/finance/accountType.txt +12 -0
  111. tdcv2/packs_data/common/finance/bic.txt +6 -0
  112. tdcv2/packs_data/common/finance/crypto.txt +18 -0
  113. tdcv2/packs_data/common/finance/currency.txt +23 -0
  114. tdcv2/packs_data/common/finance/currencyCode.txt +23 -0
  115. tdcv2/packs_data/common/finance/currencySymbol.txt +19 -0
  116. tdcv2/packs_data/common/finance/iban.txt +27 -0
  117. tdcv2/packs_data/common/finance/stockExchange.txt +18 -0
  118. tdcv2/packs_data/common/finance/tickerByCrypto/Avalanche.txt +4 -0
  119. tdcv2/packs_data/common/finance/tickerByCrypto/Bitcoin.txt +4 -0
  120. tdcv2/packs_data/common/finance/tickerByCrypto/Cardano.txt +4 -0
  121. tdcv2/packs_data/common/finance/tickerByCrypto/Chainlink.txt +4 -0
  122. tdcv2/packs_data/common/finance/tickerByCrypto/Cosmos.txt +4 -0
  123. tdcv2/packs_data/common/finance/tickerByCrypto/Dogecoin.txt +4 -0
  124. tdcv2/packs_data/common/finance/tickerByCrypto/Ethereum.txt +4 -0
  125. tdcv2/packs_data/common/finance/tickerByCrypto/Litecoin.txt +4 -0
  126. tdcv2/packs_data/common/finance/tickerByCrypto/Monero.txt +4 -0
  127. tdcv2/packs_data/common/finance/tickerByCrypto/Polkadot.txt +4 -0
  128. tdcv2/packs_data/common/finance/tickerByCrypto/Polygon.txt +4 -0
  129. tdcv2/packs_data/common/finance/tickerByCrypto/Ripple.txt +4 -0
  130. tdcv2/packs_data/common/finance/tickerByCrypto/Solana.txt +4 -0
  131. tdcv2/packs_data/common/finance/tickerByCrypto/Stellar.txt +4 -0
  132. tdcv2/packs_data/common/finance/tickerByCrypto/Tether.txt +4 -0
  133. tdcv2/packs_data/common/finance/transactionType.txt +12 -0
  134. tdcv2/packs_data/common/geo/timezone.txt +39 -0
  135. tdcv2/packs_data/common/git/sha.txt +6 -0
  136. tdcv2/packs_data/common/id/nanoid.txt +6 -0
  137. tdcv2/packs_data/common/id/object_id.txt +6 -0
  138. tdcv2/packs_data/common/id/ulid.txt +6 -0
  139. tdcv2/packs_data/common/id/uuid.txt +6 -0
  140. tdcv2/packs_data/common/internet/domain.txt +9 -0
  141. tdcv2/packs_data/common/internet/email.txt +8 -0
  142. tdcv2/packs_data/common/internet/emoji.txt +33 -0
  143. tdcv2/packs_data/common/internet/httpMethod.txt +10 -0
  144. tdcv2/packs_data/common/internet/httpStatus.txt +25 -0
  145. tdcv2/packs_data/common/internet/ipv4.txt +36 -0
  146. tdcv2/packs_data/common/internet/ipv6.txt +6 -0
  147. tdcv2/packs_data/common/internet/mac.txt +6 -0
  148. tdcv2/packs_data/common/internet/slug.txt +6 -0
  149. tdcv2/packs_data/common/internet/url.txt +9 -0
  150. tdcv2/packs_data/common/internet/userAgent.txt +9 -0
  151. tdcv2/packs_data/common/internet/username.txt +6 -0
  152. tdcv2/packs_data/common/logistics/container_iso6346.txt +34 -0
  153. tdcv2/packs_data/common/payment/card/pan.txt +36 -0
  154. tdcv2/packs_data/common/periodical/issn.txt +25 -0
  155. tdcv2/packs_data/common/phone/e164.txt +6 -0
  156. tdcv2/packs_data/common/product/ean13.txt +31 -0
  157. tdcv2/packs_data/common/product/gtin14.txt +31 -0
  158. tdcv2/packs_data/common/product/upc_a.txt +31 -0
  159. tdcv2/packs_data/common/science/chemicalElement.txt +32 -0
  160. tdcv2/packs_data/common/science/unit.txt +45 -0
  161. tdcv2/packs_data/common/security/api_key.txt +6 -0
  162. tdcv2/packs_data/common/security/jwt.txt +9 -0
  163. tdcv2/packs_data/common/security/md5.txt +6 -0
  164. tdcv2/packs_data/common/security/otp.txt +6 -0
  165. tdcv2/packs_data/common/security/sha1.txt +6 -0
  166. tdcv2/packs_data/common/security/sha256.txt +6 -0
  167. tdcv2/packs_data/common/security/totp_secret.txt +6 -0
  168. tdcv2/packs_data/common/system/cron.txt +14 -0
  169. tdcv2/packs_data/common/system/directoryPath.txt +15 -0
  170. tdcv2/packs_data/common/system/fileExt.txt +28 -0
  171. tdcv2/packs_data/common/system/mimeType.txt +23 -0
  172. tdcv2/packs_data/common/system/semver.txt +6 -0
  173. tdcv2/packs_data/common/transport/airportCode.txt +37 -0
  174. tdcv2/packs_data/common/vehicle/brand.txt +52 -0
  175. tdcv2/packs_data/common/vehicle/manufacturer.txt +41 -0
  176. tdcv2/packs_data/common/vehicle/model/Acura.txt +10 -0
  177. tdcv2/packs_data/common/vehicle/model/Alfa Romeo.txt +7 -0
  178. tdcv2/packs_data/common/vehicle/model/Aston Martin.txt +8 -0
  179. tdcv2/packs_data/common/vehicle/model/Audi.txt +17 -0
  180. tdcv2/packs_data/common/vehicle/model/BMW.txt +17 -0
  181. tdcv2/packs_data/common/vehicle/model/Bentley.txt +7 -0
  182. tdcv2/packs_data/common/vehicle/model/Bugatti.txt +6 -0
  183. tdcv2/packs_data/common/vehicle/model/Buick.txt +8 -0
  184. tdcv2/packs_data/common/vehicle/model/Cadillac.txt +11 -0
  185. tdcv2/packs_data/common/vehicle/model/Chevrolet.txt +17 -0
  186. tdcv2/packs_data/common/vehicle/model/Chrysler.txt +7 -0
  187. tdcv2/packs_data/common/vehicle/model/Dodge.txt +8 -0
  188. tdcv2/packs_data/common/vehicle/model/Ferrari.txt +10 -0
  189. tdcv2/packs_data/common/vehicle/model/Fiat.txt +9 -0
  190. tdcv2/packs_data/common/vehicle/model/Ford.txt +17 -0
  191. tdcv2/packs_data/common/vehicle/model/GMC.txt +10 -0
  192. tdcv2/packs_data/common/vehicle/model/Genesis.txt +10 -0
  193. tdcv2/packs_data/common/vehicle/model/Honda.txt +15 -0
  194. tdcv2/packs_data/common/vehicle/model/Hyundai.txt +15 -0
  195. tdcv2/packs_data/common/vehicle/model/Infiniti.txt +10 -0
  196. tdcv2/packs_data/common/vehicle/model/Jaguar.txt +10 -0
  197. tdcv2/packs_data/common/vehicle/model/Jeep.txt +12 -0
  198. tdcv2/packs_data/common/vehicle/model/Kia.txt +16 -0
  199. tdcv2/packs_data/common/vehicle/model/Lamborghini.txt +7 -0
  200. tdcv2/packs_data/common/vehicle/model/Land Rover.txt +10 -0
  201. tdcv2/packs_data/common/vehicle/model/Lexus.txt +14 -0
  202. tdcv2/packs_data/common/vehicle/model/Lincoln.txt +8 -0
  203. tdcv2/packs_data/common/vehicle/model/Lotus.txt +7 -0
  204. tdcv2/packs_data/common/vehicle/model/Lucid.txt +6 -0
  205. tdcv2/packs_data/common/vehicle/model/Maserati.txt +10 -0
  206. tdcv2/packs_data/common/vehicle/model/Maybach.txt +6 -0
  207. tdcv2/packs_data/common/vehicle/model/Mazda.txt +12 -0
  208. tdcv2/packs_data/common/vehicle/model/McLaren.txt +8 -0
  209. tdcv2/packs_data/common/vehicle/model/Mercedes-Benz.txt +17 -0
  210. tdcv2/packs_data/common/vehicle/model/Mini.txt +8 -0
  211. tdcv2/packs_data/common/vehicle/model/Mitsubishi.txt +8 -0
  212. tdcv2/packs_data/common/vehicle/model/Nissan.txt +18 -0
  213. tdcv2/packs_data/common/vehicle/model/Polestar.txt +6 -0
  214. tdcv2/packs_data/common/vehicle/model/Porsche.txt +11 -0
  215. tdcv2/packs_data/common/vehicle/model/Ram.txt +9 -0
  216. tdcv2/packs_data/common/vehicle/model/Rivian.txt +6 -0
  217. tdcv2/packs_data/common/vehicle/model/Rolls-Royce.txt +9 -0
  218. tdcv2/packs_data/common/vehicle/model/Subaru.txt +13 -0
  219. tdcv2/packs_data/common/vehicle/model/Tesla.txt +9 -0
  220. tdcv2/packs_data/common/vehicle/model/Toyota.txt +18 -0
  221. tdcv2/packs_data/common/vehicle/model/Volkswagen.txt +13 -0
  222. tdcv2/packs_data/common/vehicle/model/Volvo.txt +11 -0
  223. tdcv2/packs_data/common/vehicle/model.txt +41 -0
  224. tdcv2/packs_data/common/vehicle/vin.txt +49 -0
  225. tdcv2/packs_data/countries/usa/docs/driversLicense.txt +7 -0
  226. tdcv2/packs_data/countries/usa/docs/medicare.txt +10 -0
  227. tdcv2/packs_data/countries/usa/docs/passport.txt +7 -0
  228. tdcv2/packs_data/countries/usa/docs/ssn.txt +9 -0
  229. tdcv2/packs_data/countries/usa/education/university.txt +38 -0
  230. tdcv2/packs_data/countries/usa/finance/aba_routing.txt +23 -0
  231. tdcv2/packs_data/countries/usa/finance/accountType.txt +17 -0
  232. tdcv2/packs_data/countries/usa/finance/bank.txt +45 -0
  233. tdcv2/packs_data/countries/usa/geo/city.txt +1004 -0
  234. tdcv2/packs_data/countries/usa/geo/county.txt +183 -0
  235. tdcv2/packs_data/countries/usa/geo/state.txt +60 -0
  236. tdcv2/packs_data/countries/usa/geo/stateAbbr.txt +60 -0
  237. tdcv2/packs_data/countries/usa/geo/streetName.txt +32 -0
  238. tdcv2/packs_data/countries/usa/geo/streetNamed.txt +65 -0
  239. tdcv2/packs_data/countries/usa/geo/zip.txt +6 -0
  240. tdcv2/packs_data/countries/usa/holiday.txt +14 -0
  241. tdcv2/packs_data/countries/usa/phone.txt +6 -0
  242. tdcv2/packs_data/countries/usa/sport/team.txt +31 -0
  243. tdcv2/packs_data/countries/usa/tax/ein.txt +8 -0
  244. tdcv2/packs_data/countries/usa/tax/filingStatus.txt +10 -0
  245. tdcv2/packs_data/countries/usa/tax/itin.txt +9 -0
  246. tdcv2/packs_data/countries/usa/vehicle/plate.txt +6 -0
  247. tdcv2/packs_data/en/address/buildingType.txt +18 -0
  248. tdcv2/packs_data/en/address/unitDesignator.txt +16 -0
  249. tdcv2/packs_data/en/airline/aircraftType.txt +21 -0
  250. tdcv2/packs_data/en/airline/name.txt +32 -0
  251. tdcv2/packs_data/en/animal/bird.txt +24 -0
  252. tdcv2/packs_data/en/animal/cat.txt +19 -0
  253. tdcv2/packs_data/en/animal/dog.txt +24 -0
  254. tdcv2/packs_data/en/animal/fish.txt +22 -0
  255. tdcv2/packs_data/en/animal/horse.txt +17 -0
  256. tdcv2/packs_data/en/animal/insect.txt +19 -0
  257. tdcv2/packs_data/en/animal/type.txt +34 -0
  258. tdcv2/packs_data/en/book/format.txt +10 -0
  259. tdcv2/packs_data/en/book/genre.txt +26 -0
  260. tdcv2/packs_data/en/clothing/shoeSizeUs.txt +18 -0
  261. tdcv2/packs_data/en/clothing/size.txt +12 -0
  262. tdcv2/packs_data/en/clothing/type.txt +19 -0
  263. tdcv2/packs_data/en/color/name.txt +54 -0
  264. tdcv2/packs_data/en/commerce/carrier.txt +14 -0
  265. tdcv2/packs_data/en/commerce/department.txt +32 -0
  266. tdcv2/packs_data/en/commerce/orderStatus.txt +17 -0
  267. tdcv2/packs_data/en/commerce/paymentMethod.txt +14 -0
  268. tdcv2/packs_data/en/commerce/paymentStatus.txt +13 -0
  269. tdcv2/packs_data/en/commerce/productAdjective.txt +34 -0
  270. tdcv2/packs_data/en/commerce/productMaterial.txt +28 -0
  271. tdcv2/packs_data/en/commerce/productNoun.txt +54 -0
  272. tdcv2/packs_data/en/commerce/returnReason.txt +16 -0
  273. tdcv2/packs_data/en/commerce/reviewTitle.txt +19 -0
  274. tdcv2/packs_data/en/commerce/shippingStatus.txt +12 -0
  275. tdcv2/packs_data/en/commerce/unitOfMeasure.txt +24 -0
  276. tdcv2/packs_data/en/company/buzzAdjective.txt +44 -0
  277. tdcv2/packs_data/en/company/buzzNoun.txt +44 -0
  278. tdcv2/packs_data/en/company/buzzVerb.txt +42 -0
  279. tdcv2/packs_data/en/company/industry.txt +29 -0
  280. tdcv2/packs_data/en/company/legalSuffix.txt +24 -0
  281. tdcv2/packs_data/en/company/namePart.txt +44 -0
  282. tdcv2/packs_data/en/date/month.txt +16 -0
  283. tdcv2/packs_data/en/date/monthAbbr.txt +16 -0
  284. tdcv2/packs_data/en/date/quarter.txt +8 -0
  285. tdcv2/packs_data/en/date/season.txt +8 -0
  286. tdcv2/packs_data/en/date/timeOfDay.txt +12 -0
  287. tdcv2/packs_data/en/date/weekday.txt +11 -0
  288. tdcv2/packs_data/en/date/weekdayAbbr.txt +11 -0
  289. tdcv2/packs_data/en/education/courseSubject.txt +20 -0
  290. tdcv2/packs_data/en/education/degree.txt +18 -0
  291. tdcv2/packs_data/en/education/grade.txt +17 -0
  292. tdcv2/packs_data/en/education/major.txt +26 -0
  293. tdcv2/packs_data/en/event/type.txt +16 -0
  294. tdcv2/packs_data/en/event/venueType.txt +15 -0
  295. tdcv2/packs_data/en/finance/budgetCategory.txt +21 -0
  296. tdcv2/packs_data/en/finance/creditScoreBand.txt +9 -0
  297. tdcv2/packs_data/en/finance/insuranceType.txt +16 -0
  298. tdcv2/packs_data/en/finance/loanType.txt +13 -0
  299. tdcv2/packs_data/en/food/cuisine.txt +18 -0
  300. tdcv2/packs_data/en/food/dish.txt +29 -0
  301. tdcv2/packs_data/en/food/dishByCuisine/American.txt +11 -0
  302. tdcv2/packs_data/en/food/dishByCuisine/Chinese.txt +12 -0
  303. tdcv2/packs_data/en/food/dishByCuisine/French.txt +12 -0
  304. tdcv2/packs_data/en/food/dishByCuisine/Greek.txt +11 -0
  305. tdcv2/packs_data/en/food/dishByCuisine/Indian.txt +12 -0
  306. tdcv2/packs_data/en/food/dishByCuisine/Italian.txt +12 -0
  307. tdcv2/packs_data/en/food/dishByCuisine/Japanese.txt +12 -0
  308. tdcv2/packs_data/en/food/dishByCuisine/Korean.txt +11 -0
  309. tdcv2/packs_data/en/food/dishByCuisine/Lebanese.txt +11 -0
  310. tdcv2/packs_data/en/food/dishByCuisine/Mexican.txt +12 -0
  311. tdcv2/packs_data/en/food/dishByCuisine/Spanish.txt +11 -0
  312. tdcv2/packs_data/en/food/dishByCuisine/Thai.txt +11 -0
  313. tdcv2/packs_data/en/food/dishByCuisine/Turkish.txt +11 -0
  314. tdcv2/packs_data/en/food/dishByCuisine/Vietnamese.txt +10 -0
  315. tdcv2/packs_data/en/food/fruit.txt +26 -0
  316. tdcv2/packs_data/en/food/ingredient.txt +28 -0
  317. tdcv2/packs_data/en/food/spice.txt +24 -0
  318. tdcv2/packs_data/en/food/vegetable.txt +26 -0
  319. tdcv2/packs_data/en/gaming/characterClass.txt +20 -0
  320. tdcv2/packs_data/en/gaming/platform.txt +13 -0
  321. tdcv2/packs_data/en/gaming/rank.txt +13 -0
  322. tdcv2/packs_data/en/geo/capitalByCountry/Argentina.txt +5 -0
  323. tdcv2/packs_data/en/geo/capitalByCountry/Australia.txt +5 -0
  324. tdcv2/packs_data/en/geo/capitalByCountry/Bangladesh.txt +5 -0
  325. tdcv2/packs_data/en/geo/capitalByCountry/Brazil.txt +5 -0
  326. tdcv2/packs_data/en/geo/capitalByCountry/Canada.txt +5 -0
  327. tdcv2/packs_data/en/geo/capitalByCountry/China.txt +5 -0
  328. tdcv2/packs_data/en/geo/capitalByCountry/Egypt.txt +5 -0
  329. tdcv2/packs_data/en/geo/capitalByCountry/France.txt +5 -0
  330. tdcv2/packs_data/en/geo/capitalByCountry/Germany.txt +5 -0
  331. tdcv2/packs_data/en/geo/capitalByCountry/Greece.txt +5 -0
  332. tdcv2/packs_data/en/geo/capitalByCountry/India.txt +5 -0
  333. tdcv2/packs_data/en/geo/capitalByCountry/Indonesia.txt +5 -0
  334. tdcv2/packs_data/en/geo/capitalByCountry/Ireland.txt +5 -0
  335. tdcv2/packs_data/en/geo/capitalByCountry/Italy.txt +5 -0
  336. tdcv2/packs_data/en/geo/capitalByCountry/Japan.txt +5 -0
  337. tdcv2/packs_data/en/geo/capitalByCountry/Mexico.txt +5 -0
  338. tdcv2/packs_data/en/geo/capitalByCountry/Netherlands.txt +5 -0
  339. tdcv2/packs_data/en/geo/capitalByCountry/New Zealand.txt +5 -0
  340. tdcv2/packs_data/en/geo/capitalByCountry/Nigeria.txt +5 -0
  341. tdcv2/packs_data/en/geo/capitalByCountry/Norway.txt +5 -0
  342. tdcv2/packs_data/en/geo/capitalByCountry/Pakistan.txt +5 -0
  343. tdcv2/packs_data/en/geo/capitalByCountry/Poland.txt +5 -0
  344. tdcv2/packs_data/en/geo/capitalByCountry/Portugal.txt +5 -0
  345. tdcv2/packs_data/en/geo/capitalByCountry/Russia.txt +5 -0
  346. tdcv2/packs_data/en/geo/capitalByCountry/Saudi Arabia.txt +5 -0
  347. tdcv2/packs_data/en/geo/capitalByCountry/Singapore.txt +5 -0
  348. tdcv2/packs_data/en/geo/capitalByCountry/South Africa.txt +5 -0
  349. tdcv2/packs_data/en/geo/capitalByCountry/South Korea.txt +5 -0
  350. tdcv2/packs_data/en/geo/capitalByCountry/Spain.txt +5 -0
  351. tdcv2/packs_data/en/geo/capitalByCountry/Sweden.txt +5 -0
  352. tdcv2/packs_data/en/geo/capitalByCountry/Switzerland.txt +5 -0
  353. tdcv2/packs_data/en/geo/capitalByCountry/Thailand.txt +5 -0
  354. tdcv2/packs_data/en/geo/capitalByCountry/Turkey.txt +5 -0
  355. tdcv2/packs_data/en/geo/capitalByCountry/United Kingdom.txt +5 -0
  356. tdcv2/packs_data/en/geo/capitalByCountry/United States.txt +5 -0
  357. tdcv2/packs_data/en/geo/capitalByCountry/Vietnam.txt +5 -0
  358. tdcv2/packs_data/en/geo/country.txt +41 -0
  359. tdcv2/packs_data/en/geo/currencyByCountry/Argentina.txt +5 -0
  360. tdcv2/packs_data/en/geo/currencyByCountry/Australia.txt +5 -0
  361. tdcv2/packs_data/en/geo/currencyByCountry/Bangladesh.txt +5 -0
  362. tdcv2/packs_data/en/geo/currencyByCountry/Brazil.txt +5 -0
  363. tdcv2/packs_data/en/geo/currencyByCountry/Canada.txt +5 -0
  364. tdcv2/packs_data/en/geo/currencyByCountry/China.txt +5 -0
  365. tdcv2/packs_data/en/geo/currencyByCountry/Egypt.txt +5 -0
  366. tdcv2/packs_data/en/geo/currencyByCountry/France.txt +5 -0
  367. tdcv2/packs_data/en/geo/currencyByCountry/Germany.txt +5 -0
  368. tdcv2/packs_data/en/geo/currencyByCountry/Greece.txt +5 -0
  369. tdcv2/packs_data/en/geo/currencyByCountry/India.txt +5 -0
  370. tdcv2/packs_data/en/geo/currencyByCountry/Indonesia.txt +5 -0
  371. tdcv2/packs_data/en/geo/currencyByCountry/Ireland.txt +5 -0
  372. tdcv2/packs_data/en/geo/currencyByCountry/Italy.txt +5 -0
  373. tdcv2/packs_data/en/geo/currencyByCountry/Japan.txt +5 -0
  374. tdcv2/packs_data/en/geo/currencyByCountry/Mexico.txt +5 -0
  375. tdcv2/packs_data/en/geo/currencyByCountry/Netherlands.txt +5 -0
  376. tdcv2/packs_data/en/geo/currencyByCountry/New Zealand.txt +5 -0
  377. tdcv2/packs_data/en/geo/currencyByCountry/Nigeria.txt +5 -0
  378. tdcv2/packs_data/en/geo/currencyByCountry/Norway.txt +5 -0
  379. tdcv2/packs_data/en/geo/currencyByCountry/Pakistan.txt +5 -0
  380. tdcv2/packs_data/en/geo/currencyByCountry/Poland.txt +5 -0
  381. tdcv2/packs_data/en/geo/currencyByCountry/Portugal.txt +5 -0
  382. tdcv2/packs_data/en/geo/currencyByCountry/Russia.txt +5 -0
  383. tdcv2/packs_data/en/geo/currencyByCountry/Saudi Arabia.txt +5 -0
  384. tdcv2/packs_data/en/geo/currencyByCountry/Singapore.txt +5 -0
  385. tdcv2/packs_data/en/geo/currencyByCountry/South Africa.txt +5 -0
  386. tdcv2/packs_data/en/geo/currencyByCountry/South Korea.txt +5 -0
  387. tdcv2/packs_data/en/geo/currencyByCountry/Spain.txt +5 -0
  388. tdcv2/packs_data/en/geo/currencyByCountry/Sweden.txt +5 -0
  389. tdcv2/packs_data/en/geo/currencyByCountry/Switzerland.txt +5 -0
  390. tdcv2/packs_data/en/geo/currencyByCountry/Thailand.txt +5 -0
  391. tdcv2/packs_data/en/geo/currencyByCountry/Turkey.txt +5 -0
  392. tdcv2/packs_data/en/geo/currencyByCountry/United Kingdom.txt +5 -0
  393. tdcv2/packs_data/en/geo/currencyByCountry/United States.txt +5 -0
  394. tdcv2/packs_data/en/geo/currencyByCountry/Vietnam.txt +5 -0
  395. tdcv2/packs_data/en/geo/currencyCodeByCountry/Argentina.txt +5 -0
  396. tdcv2/packs_data/en/geo/currencyCodeByCountry/Australia.txt +5 -0
  397. tdcv2/packs_data/en/geo/currencyCodeByCountry/Bangladesh.txt +5 -0
  398. tdcv2/packs_data/en/geo/currencyCodeByCountry/Brazil.txt +5 -0
  399. tdcv2/packs_data/en/geo/currencyCodeByCountry/Canada.txt +5 -0
  400. tdcv2/packs_data/en/geo/currencyCodeByCountry/China.txt +5 -0
  401. tdcv2/packs_data/en/geo/currencyCodeByCountry/Egypt.txt +5 -0
  402. tdcv2/packs_data/en/geo/currencyCodeByCountry/France.txt +5 -0
  403. tdcv2/packs_data/en/geo/currencyCodeByCountry/Germany.txt +5 -0
  404. tdcv2/packs_data/en/geo/currencyCodeByCountry/Greece.txt +5 -0
  405. tdcv2/packs_data/en/geo/currencyCodeByCountry/India.txt +5 -0
  406. tdcv2/packs_data/en/geo/currencyCodeByCountry/Indonesia.txt +5 -0
  407. tdcv2/packs_data/en/geo/currencyCodeByCountry/Ireland.txt +5 -0
  408. tdcv2/packs_data/en/geo/currencyCodeByCountry/Italy.txt +5 -0
  409. tdcv2/packs_data/en/geo/currencyCodeByCountry/Japan.txt +5 -0
  410. tdcv2/packs_data/en/geo/currencyCodeByCountry/Mexico.txt +5 -0
  411. tdcv2/packs_data/en/geo/currencyCodeByCountry/Netherlands.txt +5 -0
  412. tdcv2/packs_data/en/geo/currencyCodeByCountry/New Zealand.txt +5 -0
  413. tdcv2/packs_data/en/geo/currencyCodeByCountry/Nigeria.txt +5 -0
  414. tdcv2/packs_data/en/geo/currencyCodeByCountry/Norway.txt +5 -0
  415. tdcv2/packs_data/en/geo/currencyCodeByCountry/Pakistan.txt +5 -0
  416. tdcv2/packs_data/en/geo/currencyCodeByCountry/Poland.txt +5 -0
  417. tdcv2/packs_data/en/geo/currencyCodeByCountry/Portugal.txt +5 -0
  418. tdcv2/packs_data/en/geo/currencyCodeByCountry/Russia.txt +5 -0
  419. tdcv2/packs_data/en/geo/currencyCodeByCountry/Saudi Arabia.txt +5 -0
  420. tdcv2/packs_data/en/geo/currencyCodeByCountry/Singapore.txt +5 -0
  421. tdcv2/packs_data/en/geo/currencyCodeByCountry/South Africa.txt +5 -0
  422. tdcv2/packs_data/en/geo/currencyCodeByCountry/South Korea.txt +5 -0
  423. tdcv2/packs_data/en/geo/currencyCodeByCountry/Spain.txt +5 -0
  424. tdcv2/packs_data/en/geo/currencyCodeByCountry/Sweden.txt +5 -0
  425. tdcv2/packs_data/en/geo/currencyCodeByCountry/Switzerland.txt +5 -0
  426. tdcv2/packs_data/en/geo/currencyCodeByCountry/Thailand.txt +5 -0
  427. tdcv2/packs_data/en/geo/currencyCodeByCountry/Turkey.txt +5 -0
  428. tdcv2/packs_data/en/geo/currencyCodeByCountry/United Kingdom.txt +5 -0
  429. tdcv2/packs_data/en/geo/currencyCodeByCountry/United States.txt +5 -0
  430. tdcv2/packs_data/en/geo/currencyCodeByCountry/Vietnam.txt +5 -0
  431. tdcv2/packs_data/en/geo/direction.txt +20 -0
  432. tdcv2/packs_data/en/government/agency.txt +13 -0
  433. tdcv2/packs_data/en/government/documentType.txt +14 -0
  434. tdcv2/packs_data/en/hacker/abbreviation.txt +40 -0
  435. tdcv2/packs_data/en/hacker/adjective.txt +24 -0
  436. tdcv2/packs_data/en/hacker/ingverb.txt +23 -0
  437. tdcv2/packs_data/en/hacker/noun.txt +30 -0
  438. tdcv2/packs_data/en/hacker/verb.txt +25 -0
  439. tdcv2/packs_data/en/hr/benefit.txt +19 -0
  440. tdcv2/packs_data/en/hr/interviewStage.txt +15 -0
  441. tdcv2/packs_data/en/hr/leaveType.txt +14 -0
  442. tdcv2/packs_data/en/hr/meetingType.txt +16 -0
  443. tdcv2/packs_data/en/legal/caseType.txt +15 -0
  444. tdcv2/packs_data/en/legal/court.txt +12 -0
  445. tdcv2/packs_data/en/legal/term.txt +16 -0
  446. tdcv2/packs_data/en/location/country.txt +241 -0
  447. tdcv2/packs_data/en/media/gameGenre.txt +19 -0
  448. tdcv2/packs_data/en/media/movieGenre.txt +21 -0
  449. tdcv2/packs_data/en/media/streamingPlatform.txt +16 -0
  450. tdcv2/packs_data/en/media/tvRating.txt +15 -0
  451. tdcv2/packs_data/en/medical/allergy.txt +21 -0
  452. tdcv2/packs_data/en/medical/ancestry.txt +16 -0
  453. tdcv2/packs_data/en/medical/bloodType.txt +12 -0
  454. tdcv2/packs_data/en/medical/diagnosis.txt +82 -0
  455. tdcv2/packs_data/en/medical/diagnosisByAncestry/Ashkenazi Jewish.txt +16 -0
  456. tdcv2/packs_data/en/medical/diagnosisByAncestry/East Asian.txt +14 -0
  457. tdcv2/packs_data/en/medical/diagnosisByAncestry/Eastern European.txt +10 -0
  458. tdcv2/packs_data/en/medical/diagnosisByAncestry/Indigenous American.txt +10 -0
  459. tdcv2/packs_data/en/medical/diagnosisByAncestry/Mediterranean.txt +11 -0
  460. tdcv2/packs_data/en/medical/diagnosisByAncestry/Middle Eastern.txt +10 -0
  461. tdcv2/packs_data/en/medical/diagnosisByAncestry/North African.txt +10 -0
  462. tdcv2/packs_data/en/medical/diagnosisByAncestry/Northern European.txt +14 -0
  463. tdcv2/packs_data/en/medical/diagnosisByAncestry/Pacific Islander.txt +10 -0
  464. tdcv2/packs_data/en/medical/diagnosisByAncestry/South Asian.txt +12 -0
  465. tdcv2/packs_data/en/medical/diagnosisByAncestry/Southeast Asian.txt +11 -0
  466. tdcv2/packs_data/en/medical/diagnosisByAncestry/Sub-Saharan African.txt +16 -0
  467. tdcv2/packs_data/en/medical/diagnosisBySpecialty/Cardiology.txt +10 -0
  468. tdcv2/packs_data/en/medical/diagnosisBySpecialty/Dermatology.txt +10 -0
  469. tdcv2/packs_data/en/medical/diagnosisBySpecialty/Endocrinology.txt +10 -0
  470. tdcv2/packs_data/en/medical/diagnosisBySpecialty/Gastroenterology.txt +10 -0
  471. tdcv2/packs_data/en/medical/diagnosisBySpecialty/Nephrology.txt +9 -0
  472. tdcv2/packs_data/en/medical/diagnosisBySpecialty/Neurology.txt +10 -0
  473. tdcv2/packs_data/en/medical/diagnosisBySpecialty/Oncology.txt +10 -0
  474. tdcv2/packs_data/en/medical/diagnosisBySpecialty/Orthopedics.txt +10 -0
  475. tdcv2/packs_data/en/medical/diagnosisBySpecialty/Psychiatry.txt +10 -0
  476. tdcv2/packs_data/en/medical/diagnosisBySpecialty/Pulmonology.txt +10 -0
  477. tdcv2/packs_data/en/medical/diagnosisFemale.txt +30 -0
  478. tdcv2/packs_data/en/medical/diagnosisMale.txt +24 -0
  479. tdcv2/packs_data/en/medical/drugGeneric.txt +38 -0
  480. tdcv2/packs_data/en/medical/specialty.txt +35 -0
  481. tdcv2/packs_data/en/medical/specialtyCoherent.txt +14 -0
  482. tdcv2/packs_data/en/medical/symptom.txt +39 -0
  483. tdcv2/packs_data/en/music/genre.txt +28 -0
  484. tdcv2/packs_data/en/music/instrument.txt +24 -0
  485. tdcv2/packs_data/en/nature/flower.txt +24 -0
  486. tdcv2/packs_data/en/nature/gemstone.txt +24 -0
  487. tdcv2/packs_data/en/nature/metal.txt +22 -0
  488. tdcv2/packs_data/en/nature/tree.txt +24 -0
  489. tdcv2/packs_data/en/person/female/diagnosis.txt +17 -0
  490. tdcv2/packs_data/en/person/female/firstName.txt +1005 -0
  491. tdcv2/packs_data/en/person/gender.txt +6 -0
  492. tdcv2/packs_data/en/person/hobby.txt +26 -0
  493. tdcv2/packs_data/en/person/householdSize.txt +11 -0
  494. tdcv2/packs_data/en/person/incomeBracket.txt +11 -0
  495. tdcv2/packs_data/en/person/language.txt +24 -0
  496. tdcv2/packs_data/en/person/lastName.txt +1005 -0
  497. tdcv2/packs_data/en/person/male/diagnosis.txt +14 -0
  498. tdcv2/packs_data/en/person/male/firstName.txt +1005 -0
  499. tdcv2/packs_data/en/person/maritalStatus.txt +11 -0
  500. tdcv2/packs_data/en/person/nationality.txt +29 -0
  501. tdcv2/packs_data/en/person/nickname.txt +44 -0
  502. tdcv2/packs_data/en/person/prefix.txt +21 -0
  503. tdcv2/packs_data/en/person/pronoun.txt +11 -0
  504. tdcv2/packs_data/en/person/suffix.txt +20 -0
  505. tdcv2/packs_data/en/person/zodiac.txt +16 -0
  506. tdcv2/packs_data/en/realestate/amenity.txt +22 -0
  507. tdcv2/packs_data/en/realestate/listingStatus.txt +14 -0
  508. tdcv2/packs_data/en/realestate/propertyType.txt +21 -0
  509. tdcv2/packs_data/en/realestate/roomType.txt +17 -0
  510. tdcv2/packs_data/en/social/contentType.txt +15 -0
  511. tdcv2/packs_data/en/social/hashtag.txt +29 -0
  512. tdcv2/packs_data/en/social/platform.txt +19 -0
  513. tdcv2/packs_data/en/social/reaction.txt +15 -0
  514. tdcv2/packs_data/en/sport/name.txt +28 -0
  515. tdcv2/packs_data/en/sport/position.txt +22 -0
  516. tdcv2/packs_data/en/sport/positionBySport/American Football.txt +10 -0
  517. tdcv2/packs_data/en/sport/positionBySport/Baseball.txt +10 -0
  518. tdcv2/packs_data/en/sport/positionBySport/Basketball.txt +9 -0
  519. tdcv2/packs_data/en/sport/positionBySport/Cricket.txt +9 -0
  520. tdcv2/packs_data/en/sport/positionBySport/Ice Hockey.txt +9 -0
  521. tdcv2/packs_data/en/sport/positionBySport/Rugby.txt +10 -0
  522. tdcv2/packs_data/en/sport/positionBySport/Soccer.txt +10 -0
  523. tdcv2/packs_data/en/sport/positionBySport/Volleyball.txt +9 -0
  524. tdcv2/packs_data/en/sport/sportCoherent.txt +12 -0
  525. tdcv2/packs_data/en/telecom/carrier.txt +16 -0
  526. tdcv2/packs_data/en/telecom/planType.txt +11 -0
  527. tdcv2/packs_data/en/text/paragraph.txt +154 -0
  528. tdcv2/packs_data/en/text/sentence.txt +504 -0
  529. tdcv2/packs_data/en/text/word.txt +404 -0
  530. tdcv2/packs_data/en/travel/bookingStatus.txt +12 -0
  531. tdcv2/packs_data/en/travel/hotelAmenity.txt +20 -0
  532. tdcv2/packs_data/en/travel/roomType.txt +17 -0
  533. tdcv2/packs_data/en/travel/starRating.txt +9 -0
  534. tdcv2/packs_data/en/travel/tripType.txt +16 -0
  535. tdcv2/packs_data/en/vehicle/bicycle.txt +16 -0
  536. tdcv2/packs_data/en/vehicle/fuel.txt +12 -0
  537. tdcv2/packs_data/en/vehicle/type.txt +18 -0
  538. tdcv2/packs_data/en/weather/condition.txt +18 -0
  539. tdcv2/packs_data/en/weather/phenomenon.txt +16 -0
  540. tdcv2/packs_data/en/word/adjective.txt +44 -0
  541. tdcv2/packs_data/en/word/adverb.txt +34 -0
  542. tdcv2/packs_data/en/word/noun.txt +44 -0
  543. tdcv2/packs_data/en/word/verb.txt +44 -0
  544. tdcv2/packs_data/en/work/cable/conduit.txt +11 -0
  545. tdcv2/packs_data/en/work/cable/type.txt +13 -0
  546. tdcv2/packs_data/en/work/department.txt +24 -0
  547. tdcv2/packs_data/en/work/employmentType.txt +13 -0
  548. tdcv2/packs_data/en/work/industryCoherent.txt +14 -0
  549. tdcv2/packs_data/en/work/jobByIndustry/Construction.txt +10 -0
  550. tdcv2/packs_data/en/work/jobByIndustry/Education.txt +10 -0
  551. tdcv2/packs_data/en/work/jobByIndustry/Finance.txt +10 -0
  552. tdcv2/packs_data/en/work/jobByIndustry/Healthcare.txt +10 -0
  553. tdcv2/packs_data/en/work/jobByIndustry/Hospitality.txt +10 -0
  554. tdcv2/packs_data/en/work/jobByIndustry/Legal.txt +10 -0
  555. tdcv2/packs_data/en/work/jobByIndustry/Manufacturing.txt +10 -0
  556. tdcv2/packs_data/en/work/jobByIndustry/Retail.txt +10 -0
  557. tdcv2/packs_data/en/work/jobByIndustry/Technology.txt +10 -0
  558. tdcv2/packs_data/en/work/jobByIndustry/Transportation.txt +10 -0
  559. tdcv2/packs_data/en/work/jobTitle.txt +189 -0
  560. tdcv2/packs_data/en/work/mining/method.txt +12 -0
  561. tdcv2/packs_data/en/work/mining/mineral.txt +21 -0
  562. tdcv2/packs_data/en/work/mining/shift.txt +9 -0
  563. tdcv2/packs_data/en/work/seniority.txt +20 -0
  564. tdcv2/packs_data/en/work/skill.txt +44 -0
  565. tdcv2/packs_data/en/work/trucking/cargoType.txt +17 -0
  566. tdcv2/packs_data/en/work/trucking/licenceClass.txt +7 -0
  567. tdcv2/packs_data/en/work/trucking/routeType.txt +11 -0
  568. tdcv2/packs_data/en/world/religion.txt +17 -0
  569. tdcv2/packs_data/en/world/writingSystem.txt +16 -0
  570. tdcv2/packs_data/index.txt +489 -0
  571. tdcv2/parser/__init__.py +5 -0
  572. tdcv2/parser/config_builder.py +516 -0
  573. tdcv2/parser/facade.py +137 -0
  574. tdcv2/parser/generated/TDCLexer.py +160 -0
  575. tdcv2/parser/generated/TDCParser.py +870 -0
  576. tdcv2/parser/generated/TDCParserVisitor.py +72 -0
  577. tdcv2/parser/generated/__init__.py +0 -0
  578. tdcv2/pattern/__init__.py +5 -0
  579. tdcv2/pattern/curve.py +301 -0
  580. tdcv2/pattern/density.py +133 -0
  581. tdcv2/pattern/gen.py +261 -0
  582. tdcv2/pattern/png.py +178 -0
  583. tdcv2/pattern/svg.py +424 -0
  584. tdcv2/prng/__init__.py +6 -0
  585. tdcv2/prng/permute.py +102 -0
  586. tdcv2/prng/prng.py +141 -0
  587. tdcv2/prng/rand.py +34 -0
  588. tdcv2/prng/seekable.py +60 -0
  589. tdcv2/sequence/__init__.py +5 -0
  590. tdcv2/sequence/pool.py +132 -0
  591. tdcv2/sequence/uniq.py +264 -0
  592. tdcv2/sequence/uniq_simple.py +175 -0
  593. tdcv2/stats/__init__.py +5 -0
  594. tdcv2/stats/distribution.py +249 -0
  595. tdcv2/stats/special.py +174 -0
  596. tdcv2/stats/timeseries.py +89 -0
  597. tdcv2/tdc.py +465 -0
  598. tdcv2/unicode/__init__.py +5 -0
  599. tdcv2/unicode/alphabets.py +59 -0
  600. tdcv2/unicode/char_set.py +57 -0
  601. tdcv2/validator/__init__.py +5 -0
  602. tdcv2/validator/checks.py +101 -0
  603. tdcv2/validator/compute_check.py +324 -0
  604. tdcv2/validator/validate.py +2912 -0
  605. tdcv2-0.1.2.dist-info/METADATA +230 -0
  606. tdcv2-0.1.2.dist-info/RECORD +610 -0
  607. tdcv2-0.1.2.dist-info/WHEEL +5 -0
  608. tdcv2-0.1.2.dist-info/entry_points.txt +2 -0
  609. tdcv2-0.1.2.dist-info/licenses/LICENSE +21 -0
  610. tdcv2-0.1.2.dist-info/top_level.txt +1 -0
tdcv2/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ """TDC — The Data Constructor. Deterministic test data from a declarative config."""
2
+
3
+ from .errors import Diagnostic, Severity, TdcError
4
+ from .tdc import TDC, Row, SeedInfo
5
+
6
+ __all__ = ["TDC", "Diagnostic", "Row", "SeedInfo", "Severity", "TdcError"]
tdcv2/cli/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """The ``tdcv2`` command line.
2
+
3
+ Nothing is imported here on purpose: ``python -m tdcv2.cli.main`` would otherwise warn about the
4
+ module being loaded twice, and the ordinary library import has no reason to pull the CLI in.
5
+ """
tdcv2/cli/__main__.py ADDED
@@ -0,0 +1,5 @@
1
+ """``python -m tdcv2.cli`` — the same entry point as the installed ``tdcv2`` command."""
2
+
3
+ from .main import cli
4
+
5
+ cli()
tdcv2/cli/args.py ADDED
@@ -0,0 +1,149 @@
1
+ """Command-line arguments, parsed by hand.
2
+
3
+ `argparse` was the obvious choice and the wrong one. The TypeScript CLI is the interface users
4
+ already know, and matching it exactly matters more than saving fifty lines: `--engine 2` and
5
+ `--engine=2` both work there, an unknown flag is exit code 2 with a specific message, and a
6
+ positional argument may follow flags. Getting argparse to agree on all of that costs more than
7
+ writing the loop, and leaves the agreement undocumented.
8
+
9
+ Kept apart from `main` so the parsing can be tested without a filesystem or a run.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from dataclasses import dataclass, field
15
+
16
+
17
+ class UsageError(ValueError):
18
+ """A command line that cannot be obeyed. Reported, then exit code 2."""
19
+
20
+
21
+ @dataclass(frozen=True, slots=True)
22
+ class Options:
23
+ """What the command line asked for, before anything has been read or run."""
24
+
25
+ input: str | None = None
26
+ output: str | None = None
27
+ seed: str | None = None
28
+ count: int | None = None
29
+ locale: str | None = None
30
+ data_paths: list[str] = field(default_factory=list)
31
+ jobs: int | None = None
32
+ mode: str | None = None
33
+ engine: int | None = None
34
+ help: bool = False
35
+ version: bool = False
36
+
37
+
38
+ #: Flags that take a value, in both the `--flag value` and `--flag=value` spellings.
39
+ _VALUED = (
40
+ "--output",
41
+ "--seed",
42
+ "--count",
43
+ "--locale",
44
+ "--data-path",
45
+ "--jobs",
46
+ "--mode",
47
+ "--engine",
48
+ )
49
+
50
+
51
+ def parse(argv: list[str]) -> Options:
52
+ """The generate command's arguments. Raises `UsageError` with the message to print."""
53
+ out: dict[str, object] = {"data_paths": []}
54
+ i = 0
55
+ while i < len(argv):
56
+ arg = argv[i]
57
+
58
+ name, value = _split(arg)
59
+ if name in _VALUED:
60
+ if value is None:
61
+ i += 1
62
+ if i >= len(argv) or argv[i] == "":
63
+ raise UsageError(f"missing value for {name}")
64
+ value = argv[i]
65
+ _store(out, name, value)
66
+ i += 1
67
+ continue
68
+
69
+ if arg in ("-o", "--output"):
70
+ i += 1
71
+ if i >= len(argv):
72
+ raise UsageError("missing value for --output")
73
+ out["output"] = argv[i]
74
+ elif arg in ("-h", "--help"):
75
+ out["help"] = True
76
+ elif arg in ("-v", "--version"):
77
+ out["version"] = True
78
+ elif arg == "--stream":
79
+ # The legacy spelling of --engine 2, kept because configs and scripts still say it.
80
+ out["engine"] = 2
81
+ elif arg == "--disk":
82
+ out["mode"] = "disk"
83
+ elif arg.startswith("-"):
84
+ raise UsageError(f"unknown option: {arg}")
85
+ elif out.get("input") is None:
86
+ out["input"] = arg
87
+ else:
88
+ raise UsageError(f"unexpected positional argument: {arg}")
89
+ i += 1
90
+
91
+ return Options(**out) # type: ignore[arg-type]
92
+
93
+
94
+ def _split(arg: str) -> tuple[str, str | None]:
95
+ """`--flag=value` into its parts; anything else unchanged with no value."""
96
+ if arg.startswith("--") and "=" in arg:
97
+ name, _, value = arg.partition("=")
98
+ if value == "":
99
+ raise UsageError(f"missing value for {name}")
100
+ return name, value
101
+ return arg, None
102
+
103
+
104
+ def _store(out: dict[str, object], name: str, value: str) -> None:
105
+ if name == "--output":
106
+ out["output"] = value
107
+ elif name == "--seed":
108
+ out["seed"] = value
109
+ elif name == "--locale":
110
+ out["locale"] = value
111
+ elif name == "--data-path":
112
+ paths = out["data_paths"]
113
+ assert isinstance(paths, list)
114
+ paths.append(value)
115
+ elif name == "--count":
116
+ out["count"] = _non_negative(value, "--count")
117
+ elif name == "--jobs":
118
+ out["jobs"] = _positive(value, "--jobs")
119
+ elif name == "--engine":
120
+ if value not in ("1", "2", "3"):
121
+ raise UsageError(
122
+ f'invalid --engine "{value}" — expected 1 (in-memory), 2 (streaming), '
123
+ "or 3 (exact-on-disk)"
124
+ )
125
+ out["engine"] = int(value)
126
+ elif name == "--mode":
127
+ if value not in ("memory", "disk"):
128
+ raise UsageError(f'invalid --mode "{value}" — expected "memory" or "disk"')
129
+ out["mode"] = value
130
+
131
+
132
+ def _non_negative(value: str, flag: str) -> int:
133
+ try:
134
+ parsed = int(value)
135
+ except ValueError:
136
+ raise UsageError(f'invalid {flag} "{value}" — expected a non-negative integer') from None
137
+ if parsed < 0:
138
+ raise UsageError(f'invalid {flag} "{value}" — expected a non-negative integer')
139
+ return parsed
140
+
141
+
142
+ def _positive(value: str, flag: str) -> int:
143
+ try:
144
+ parsed = int(value)
145
+ except ValueError:
146
+ raise UsageError(f'invalid {flag} "{value}" — expected a positive integer') from None
147
+ if parsed < 1:
148
+ raise UsageError(f'invalid {flag} "{value}" — expected a positive integer')
149
+ return parsed
tdcv2/cli/init.py ADDED
@@ -0,0 +1,206 @@
1
+ """``tdcv2 init`` — create a config file by asking, rather than by making anyone hand-write JSON.
2
+
3
+ People want to generate data, not learn a config format. In a real terminal this runs a short
4
+ wizard — where the config should live, where downloaded packs go, which locale — and writes the
5
+ file. With no terminal, in a script or in CI, it takes the answers from flags instead, so it stays
6
+ scriptable and testable.
7
+
8
+ The decisions are pure functions; the wizard is a thin shell over them. That is what the tests
9
+ exercise, because a prompt is hard to test and a decision is not.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import sys
16
+ from dataclasses import dataclass
17
+ from pathlib import Path
18
+
19
+ from ..packs import project_config
20
+
21
+ USAGE = """Usage: tdcv2 init [options]
22
+
23
+ -g, --global Write the per-user config instead of a project one
24
+ -y, --yes Take the defaults, ask nothing
25
+ -f, --force Overwrite an existing config
26
+ --locale <loc> Default locale for the config (default: en)
27
+ --data-path <dir> Folder for downloaded packs
28
+ """
29
+
30
+
31
+ class InitError(ValueError):
32
+ """A command line `init` cannot obey."""
33
+
34
+
35
+ @dataclass(frozen=True, slots=True)
36
+ class Plan:
37
+ """Everything decided, nothing written yet."""
38
+
39
+ path: Path
40
+ pack_store: Path
41
+ locale: str
42
+ is_global: bool
43
+
44
+
45
+ def config_target(is_global: bool, cwd: Path) -> Path:
46
+ """Where the config goes: the project's own folder, or the per-user location."""
47
+ if not is_global:
48
+ return cwd.resolve() / project_config.CONFIG_NAME
49
+ target = project_config.global_config_path()
50
+ if target is None: # pragma: no cover — every supported platform has one
51
+ raise InitError("no global config location on this platform — use a project config")
52
+ return target
53
+
54
+
55
+ def default_pack_store(is_global: bool, config_path: Path, cwd: Path) -> Path:
56
+ """A project keeps packs beside its config; the global config keeps them next to itself."""
57
+ return config_path.parent / "packs" if is_global else cwd.resolve() / "tdcv2-packs"
58
+
59
+
60
+ def config_content(plan: Plan) -> str:
61
+ """The file's JSON.
62
+
63
+ The store is written as ``packStore``, not as a ``dataPaths`` entry: it is where ``pack add``
64
+ downloads bundles, and it is deliberately not a scan root on its own — each installed bundle
65
+ registers its own ``packs`` folder, so that addresses stay ``en.person.lastName`` rather than
66
+ ``en.packs.en.person.lastName``. A project config stores the path relative, so the file can be
67
+ checked into git and still work on another machine; a global config is machine-specific by
68
+ nature and stores it absolute.
69
+ """
70
+ store = (
71
+ str(plan.pack_store) if plan.is_global else _relative_to(plan.path.parent, plan.pack_store)
72
+ )
73
+ return (
74
+ json.dumps({"packStore": store, "locale": plan.locale}, indent=2, ensure_ascii=False) + "\n"
75
+ )
76
+
77
+
78
+ def _relative_to(base: Path, target: Path) -> str:
79
+ absolute, root = target.resolve(), base.resolve()
80
+ if absolute == root:
81
+ return "."
82
+ try:
83
+ return "./" + absolute.relative_to(root).as_posix()
84
+ except ValueError:
85
+ return str(absolute)
86
+
87
+
88
+ def write_config(plan: Plan, force: bool) -> None:
89
+ """Write it, and create the pack folder so ``pack add`` has somewhere to go."""
90
+ if plan.path.exists() and not force:
91
+ raise InitError(
92
+ f'config already exists at "{plan.path}" — pass --force to overwrite, '
93
+ "or edit it directly"
94
+ )
95
+ plan.path.parent.mkdir(parents=True, exist_ok=True)
96
+ plan.path.write_text(config_content(plan), encoding="utf-8")
97
+ plan.pack_store.mkdir(parents=True, exist_ok=True)
98
+
99
+
100
+ @dataclass(frozen=True, slots=True)
101
+ class Flags:
102
+ is_global: bool = False
103
+ force: bool = False
104
+ yes: bool = False
105
+ locale: str | None = None
106
+ pack_store: str | None = None
107
+
108
+
109
+ def parse_flags(argv: list[str]) -> Flags:
110
+ out: dict[str, object] = {}
111
+ i = 0
112
+ while i < len(argv):
113
+ arg = argv[i]
114
+ if arg in ("-g", "--global"):
115
+ out["is_global"] = True
116
+ elif arg in ("-f", "--force"):
117
+ out["force"] = True
118
+ elif arg in ("-y", "--yes"):
119
+ out["yes"] = True
120
+ elif arg.startswith("--locale="):
121
+ out["locale"] = arg[len("--locale=") :]
122
+ elif arg.startswith("--data-path="):
123
+ out["pack_store"] = arg[len("--data-path=") :]
124
+ elif arg in ("--locale", "--data-path"):
125
+ i += 1
126
+ if i >= len(argv):
127
+ raise InitError(f"missing value for {arg}")
128
+ out["locale" if arg == "--locale" else "pack_store"] = argv[i]
129
+ else:
130
+ raise InitError(f"unknown option for init: {arg}")
131
+ i += 1
132
+ return Flags(**out) # type: ignore[arg-type]
133
+
134
+
135
+ def plan_from_flags(flags: Flags, cwd: Path) -> Plan:
136
+ path = config_target(flags.is_global, cwd)
137
+ store = (
138
+ (cwd / flags.pack_store).resolve()
139
+ if flags.pack_store
140
+ else default_pack_store(flags.is_global, path, cwd)
141
+ )
142
+ return Plan(path, store, flags.locale or "en", flags.is_global)
143
+
144
+
145
+ def run_init(argv: list[str], cwd: Path | None = None) -> int:
146
+ here = (cwd or Path.cwd()).resolve()
147
+
148
+ if any(a in ("-h", "--help") for a in argv):
149
+ sys.stdout.write(USAGE)
150
+ return 0
151
+
152
+ try:
153
+ flags = parse_flags(argv)
154
+ except InitError as e:
155
+ sys.stderr.write(f"tdcv2: {e}\nRun `tdcv2 init --help` for usage.\n")
156
+ return 2
157
+
158
+ interactive = sys.stdin.isatty() and sys.stdout.isatty() and not flags.yes
159
+ try:
160
+ plan = _ask(flags, here) if interactive else plan_from_flags(flags, here)
161
+ except (EOFError, KeyboardInterrupt):
162
+ sys.stderr.write("\ntdcv2: cancelled\n")
163
+ return 1
164
+ except InitError as e:
165
+ sys.stderr.write(f"tdcv2: {e}\n")
166
+ return 2
167
+
168
+ try:
169
+ write_config(plan, flags.force)
170
+ except (InitError, OSError) as e:
171
+ sys.stderr.write(f"tdcv2: {e}\n")
172
+ return 2
173
+
174
+ sys.stdout.write(
175
+ f"Wrote {'global' if plan.is_global else 'project'} config: {plan.path}\n"
176
+ f" data packs → {plan.pack_store}\n"
177
+ f" locale → {plan.locale}\n"
178
+ f"\nNext: run `tdcv2 pack` to download data packs into that folder.\n"
179
+ )
180
+ return 0
181
+
182
+
183
+ def _ask(flags: Flags, cwd: Path) -> Plan:
184
+ """The wizard. Plain `input`, because one dependency for three questions is not worth it."""
185
+ is_global = flags.is_global
186
+ if not flags.pack_store and not flags.is_global:
187
+ answer = input(
188
+ "Where should this config live?\n"
189
+ " 1) This project — a tdcv2.config.json here, check it into git\n"
190
+ " 2) Global — all your projects, in your home folder\n"
191
+ "Choice [1]: "
192
+ ).strip()
193
+ is_global = answer == "2"
194
+
195
+ path = config_target(is_global, cwd)
196
+ suggested = (
197
+ (cwd / flags.pack_store).resolve()
198
+ if flags.pack_store
199
+ else default_pack_store(is_global, path, cwd)
200
+ )
201
+
202
+ typed = input(f"Folder for downloaded data packs [{suggested}]: ").strip()
203
+ store = (cwd / typed).resolve() if typed else suggested
204
+
205
+ locale = input(f"Default locale [{flags.locale or 'en'}]: ").strip()
206
+ return Plan(path, store, locale or flags.locale or "en", is_global)
tdcv2/cli/main.py ADDED
@@ -0,0 +1,299 @@
1
+ """``tdcv2`` — the command line.
2
+
3
+ The library is the recommended way to embed TDC; this exists so that a `.tdc` file can be run
4
+ without writing a program around it, and so that a Python user never needs another language's
5
+ toolchain to do it. The surface deliberately matches the TypeScript CLI flag for flag: the same
6
+ config run through either must behave the same way, including its exit codes.
7
+
8
+ Three commands beyond generating:
9
+
10
+ * ``init`` — write a ``tdcv2.config.json``, by asking rather than by making anyone hand-write JSON
11
+ * ``pack`` — list, install and remove data packs from the shared registry
12
+ * ``check`` — validate a config and say nothing when it is fine
13
+
14
+ Exit codes: 0 fine, 1 the run failed (an invalid config, a refused preflight), 2 the command line
15
+ itself was wrong.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import sys
21
+ from pathlib import Path
22
+
23
+ from ..errors import Diagnostic, Severity, TdcError, format_diagnostic, format_diagnostics
24
+ from .args import Options, UsageError, parse
25
+
26
+
27
+ def _version() -> str:
28
+ """The installed distribution's version, not a second copy of it.
29
+
30
+ A hand-written constant here is a number that agrees with itself and with
31
+ nothing else: bumping ``pyproject.toml`` for a release left ``tdcv2
32
+ --version`` reporting the old one, silently. The TypeScript package had
33
+ exactly this bug and it went unnoticed through a release. The fallback
34
+ covers running from a source tree that was never installed, where there is
35
+ no distribution to ask.
36
+ """
37
+ from importlib.metadata import PackageNotFoundError, version
38
+
39
+ try:
40
+ return version("tdcv2")
41
+ except PackageNotFoundError:
42
+ return "0+unknown"
43
+
44
+
45
+ VERSION = _version()
46
+
47
+ HELP = """tdcv2 — The Data Constructor
48
+
49
+ Usage:
50
+ tdcv2 <input.tdc> [options] Generate data from a config
51
+ tdcv2 init [--global] Set up a config (asks where; --yes for defaults)
52
+ tdcv2 pack [list|add|remove <id>] Install / remove data packs (list with no args)
53
+ tdcv2 check <input.tdc> Validate a config without generating anything
54
+ tdcv2 format [-w] <file.tdc> Pretty-print a config (-w writes it in place)
55
+
56
+ Options:
57
+ -o, --output <path> Write generated content to <path> (default: stdout)
58
+ --seed <seed> Override the seed declared in <env>
59
+ --count <n> Override the count declared in <env>
60
+ --locale <loc> Override the default locale (default: en)
61
+ --data-path <dir> Add a data folder for @data/... sources (repeatable)
62
+ --jobs <n> Split the run across n processes. Same output either
63
+ way — a pure speed knob. Needs -o and the streaming
64
+ engine; ignored where the run cannot be split
65
+ --mode <memory|disk> Advanced. disk (default): bounded memory, scales to
66
+ any size — TDC picks the streaming or exact engine
67
+ automatically from the config. memory: the small,
68
+ in-RAM engine (an escape hatch; does not scale)
69
+ --disk Shortcut for --mode disk (already the default)
70
+ --engine <1|2|3> Advanced: force a specific engine
71
+ --stream Legacy alias for --engine 2
72
+ -h, --help Show this message
73
+ -v, --version Show version and exit
74
+
75
+ Data paths also come from tdcv2.config.json (nearest one up from the current
76
+ directory) and the global config — { "dataPaths": [...], "locale": ".." }.
77
+ Order of priority: --data-path > project config > global config > bundled packs.
78
+
79
+ See https://github.com/NickLiapin/tdcv2 for the DSL reference.
80
+ """
81
+
82
+
83
+ def main(argv: list[str] | None = None) -> int:
84
+ """Run the CLI. Returns the exit code rather than calling `exit`, so tests can drive it."""
85
+ args = list(sys.argv[1:] if argv is None else argv)
86
+
87
+ if args and args[0] == "init":
88
+ from .init import run_init
89
+
90
+ return run_init(args[1:])
91
+ if args and args[0] == "pack":
92
+ from .pack import run_pack
93
+
94
+ return run_pack(args[1:])
95
+ if args and args[0] == "check":
96
+ return _check(args[1:])
97
+ if args and args[0] == "format":
98
+ return _format(args[1:])
99
+
100
+ try:
101
+ options = parse(args)
102
+ except UsageError as e:
103
+ _fail(str(e), usage=True)
104
+ return 2
105
+
106
+ if options.help:
107
+ sys.stdout.write(HELP)
108
+ return 0
109
+ if options.version:
110
+ sys.stdout.write(f"tdcv2 {VERSION}\n")
111
+ return 0
112
+ if options.input is None:
113
+ _fail("input file is required", usage=True)
114
+ return 2
115
+
116
+ return _generate(options)
117
+
118
+
119
+ def cli() -> None:
120
+ """The console-script entry point: run, then exit with the code."""
121
+ raise SystemExit(main())
122
+
123
+
124
+ def _generate(options: Options) -> int:
125
+ from ..tdc import TDC
126
+
127
+ try:
128
+ data = TDC(
129
+ options.input,
130
+ count=options.count,
131
+ seed=options.seed,
132
+ locale=options.locale,
133
+ data_paths=[Path(p) for p in options.data_paths] or None,
134
+ engine=options.engine if options.engine is not None else _engine_for(options.mode),
135
+ )
136
+ except TdcError as e:
137
+ _report(e.diagnostics, options.input, e.source)
138
+ return 1
139
+ except (OSError, ValueError, RuntimeError) as e:
140
+ # RuntimeError covers the engines' refusals (an infeasible uniq, a
141
+ # forced streaming engine on a whole-column config) — the reference
142
+ # prints these as one line, never a stack trace.
143
+ _fail(str(e))
144
+ return 1
145
+
146
+ _report(data.diagnostics, options.input, data.source)
147
+
148
+ # A run with no seed anywhere gets a random one. Print it, or the output cannot be reproduced —
149
+ # which is the one promise the whole library is built to keep.
150
+ seed = data.seed_info()
151
+ if seed.generated:
152
+ _note(
153
+ f'no seed specified — using random seed "{seed.seed}". '
154
+ f'Re-run with --seed "{seed.seed}" to reproduce this exact output.'
155
+ )
156
+
157
+ # Ask what the run will cost before starting it. A config that cannot fit says so in a
158
+ # millisecond here and takes minutes to say so by thrashing.
159
+ budget = data.preflight(materialized=options.output is None)
160
+ if budget is not None:
161
+ _report_one(budget, options.input, data.source)
162
+ if budget.severity is Severity.ERROR:
163
+ return 1
164
+
165
+ try:
166
+ if options.output is not None:
167
+ data.write_file(options.output, workers=options.jobs)
168
+ else:
169
+ # Straight to stdout in one write per record batch rather than per record: a syscall a
170
+ # row is most of the cost of a large run that is not being written to a file.
171
+ sys.stdout.write(str(data))
172
+ except (OSError, ValueError, RuntimeError) as e:
173
+ # RuntimeError is the engines' refusal channel (an infeasible uniq, a
174
+ # forced streaming engine on a whole-column config): one line, exit 1,
175
+ # never a stack trace — the reference's behavior.
176
+ _fail(str(e))
177
+ return 1
178
+ return 0
179
+
180
+
181
+ def _check(argv: list[str]) -> int:
182
+ """``tdcv2 check <file>`` — the validator alone, for an editor or a pre-commit hook."""
183
+ files = [a for a in argv if not a.startswith("-")]
184
+ if len(argv) != len(files) or len(files) != 1:
185
+ _fail("usage: tdcv2 check <input.tdc>")
186
+ return 2
187
+
188
+ from ..tdc import TDC
189
+
190
+ try:
191
+ data = TDC(files[0])
192
+ except TdcError as e:
193
+ _report(e.diagnostics, files[0], e.source)
194
+ return 1
195
+ except (OSError, ValueError) as e:
196
+ _fail(str(e))
197
+ return 1
198
+
199
+ problems = data.diagnostics
200
+ _report(problems, files[0], data.source)
201
+ if not problems:
202
+ sys.stderr.write(f"tdcv2: {files[0]} is valid\n")
203
+ return 0
204
+
205
+
206
+ def _format(argv: list[str]) -> int:
207
+ """``tdcv2 format [-w] <file.tdc>`` — pretty-print a config.
208
+
209
+ Prints to stdout by default; ``-w`` overwrites the file. A file with a syntax error is
210
+ reported and left alone: reformatting something that cannot be parsed would be a guess about
211
+ what the author meant.
212
+ """
213
+ write = False
214
+ files: list[str] = []
215
+ for arg in argv:
216
+ if arg in ("-w", "--write"):
217
+ write = True
218
+ elif arg in ("-h", "--help"):
219
+ sys.stdout.write("Usage: tdcv2 format [-w|--write] <file.tdc>\n")
220
+ return 0
221
+ elif arg.startswith("-"):
222
+ _fail(f"format: unknown option: {arg}")
223
+ return 2
224
+ else:
225
+ files.append(arg)
226
+
227
+ if len(files) != 1:
228
+ _fail("format: a .tdc file is required")
229
+ return 2
230
+
231
+ from ..formatter import format_tdc
232
+
233
+ path = Path(files[0])
234
+ try:
235
+ source = path.read_text(encoding="utf-8")
236
+ except OSError as e:
237
+ _fail(f"format: cannot read {files[0]}: {e}")
238
+ return 1
239
+
240
+ # Never format a file we cannot fully parse — report the syntax error instead.
241
+ from ..parser import facade
242
+
243
+ parsed = facade.parse(source)
244
+ if not parsed.ok:
245
+ problems = [
246
+ Diagnostic.error("TDC001", p.message, "", p.line, p.column) for p in parsed.problems
247
+ ]
248
+ _report(problems, files[0], source)
249
+ return 1
250
+
251
+ formatted = format_tdc(source)
252
+ if not write:
253
+ sys.stdout.write(formatted)
254
+ return 0
255
+
256
+ if formatted != source:
257
+ # Write beside the file and rename over it: a crash mid-write must not
258
+ # leave the user's config truncated.
259
+ tmp = path.with_name(path.name + ".tmp")
260
+ tmp.write_text(formatted, encoding="utf-8")
261
+ tmp.replace(path)
262
+ _note(f"formatted {files[0]}")
263
+ else:
264
+ _note(f"{files[0]} is already formatted")
265
+ return 0
266
+
267
+
268
+ def _engine_for(mode: str | None) -> int | None:
269
+ """``--mode memory`` is the in-memory engine by name; ``disk`` is the default already."""
270
+ return 1 if mode == "memory" else None
271
+
272
+
273
+ def _report(problems: list[Diagnostic], filename: str | None, source: str | None = None) -> None:
274
+ """Diagnostics to stderr, so they stay out of a piped or redirected run's data."""
275
+ if not problems:
276
+ return
277
+ sys.stderr.write(
278
+ format_diagnostics(problems, source, filename or "<input>", sys.stderr.isatty()) + "\n"
279
+ )
280
+
281
+
282
+ def _report_one(problem: Diagnostic, filename: str | None, source: str | None = None) -> None:
283
+ sys.stderr.write(
284
+ format_diagnostic(problem, source, filename or "<input>", sys.stderr.isatty()) + "\n"
285
+ )
286
+
287
+
288
+ def _fail(message: str, usage: bool = False) -> None:
289
+ sys.stderr.write(f"tdcv2: {message}\n")
290
+ if usage:
291
+ sys.stderr.write("Run `tdcv2 --help` for usage.\n")
292
+
293
+
294
+ def _note(message: str) -> None:
295
+ sys.stderr.write(f"tdcv2: {message}\n")
296
+
297
+
298
+ if __name__ == "__main__":
299
+ cli()