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.
- tdcv2/__init__.py +6 -0
- tdcv2/cli/__init__.py +5 -0
- tdcv2/cli/__main__.py +5 -0
- tdcv2/cli/args.py +149 -0
- tdcv2/cli/init.py +206 -0
- tdcv2/cli/main.py +299 -0
- tdcv2/cli/pack.py +276 -0
- tdcv2/cli/pack_picker.py +975 -0
- tdcv2/compute/__init__.py +6 -0
- tdcv2/compute/encode.py +59 -0
- tdcv2/compute/evaluate.py +384 -0
- tdcv2/compute/value.py +125 -0
- tdcv2/date/__init__.py +5 -0
- tdcv2/date/formatter.py +163 -0
- tdcv2/date/gen.py +225 -0
- tdcv2/date/locales.py +481 -0
- tdcv2/date/parse.py +83 -0
- tdcv2/date/plain.py +142 -0
- tdcv2/distribution/__init__.py +5 -0
- tdcv2/distribution/hamilton.py +78 -0
- tdcv2/distribution/percent_mask.py +98 -0
- tdcv2/engine/__init__.py +5 -0
- tdcv2/engine/_shard.py +47 -0
- tdcv2/engine/disk.py +32 -0
- tdcv2/engine/exact_uniq.py +326 -0
- tdcv2/engine/external_sort.py +89 -0
- tdcv2/engine/memory.py +1739 -0
- tdcv2/engine/parallel.py +138 -0
- tdcv2/engine/per_row.py +323 -0
- tdcv2/engine/repeat_keyed.py +158 -0
- tdcv2/engine/router.py +202 -0
- tdcv2/engine/stream.py +1406 -0
- tdcv2/errors/__init__.py +14 -0
- tdcv2/errors/diagnostic.py +95 -0
- tdcv2/errors/render.py +200 -0
- tdcv2/expr/__init__.py +6 -0
- tdcv2/expr/evaluate.py +205 -0
- tdcv2/expr/parse.py +295 -0
- tdcv2/format/__init__.py +5 -0
- tdcv2/format/interpolate.py +136 -0
- tdcv2/format/mask.py +202 -0
- tdcv2/format/transforms.py +226 -0
- tdcv2/formatter/__init__.py +5 -0
- tdcv2/formatter/format.py +301 -0
- tdcv2/generators/__init__.py +25 -0
- tdcv2/generators/accumulate.py +163 -0
- tdcv2/generators/advanced_regex.py +596 -0
- tdcv2/generators/counter.py +19 -0
- tdcv2/generators/file.py +423 -0
- tdcv2/generators/http.py +208 -0
- tdcv2/generators/imperfections.py +133 -0
- tdcv2/generators/number.py +409 -0
- tdcv2/generators/regex.py +485 -0
- tdcv2/generators/repeat.py +203 -0
- tdcv2/generators/symbol.py +82 -0
- tdcv2/lib/__init__.py +5 -0
- tdcv2/lib/numbers.py +74 -0
- tdcv2/lib/text.py +31 -0
- tdcv2/model/__init__.py +33 -0
- tdcv2/model/config.py +272 -0
- tdcv2/output/__init__.py +5 -0
- tdcv2/output/column_type.py +153 -0
- tdcv2/output/columns.py +219 -0
- tdcv2/output/parquet/__init__.py +27 -0
- tdcv2/output/parquet/convert.py +244 -0
- tdcv2/output/parquet/dictionary.py +66 -0
- tdcv2/output/parquet/list_levels.py +75 -0
- tdcv2/output/parquet/plain.py +124 -0
- tdcv2/output/parquet/rle.py +108 -0
- tdcv2/output/parquet/schema.py +131 -0
- tdcv2/output/parquet/snappy.py +129 -0
- tdcv2/output/parquet/statistics.py +124 -0
- tdcv2/output/parquet/thrift.py +136 -0
- tdcv2/output/parquet/writer.py +522 -0
- tdcv2/output/parquet_output.py +134 -0
- tdcv2/packs/__init__.py +17 -0
- tdcv2/packs/data_packs.py +274 -0
- tdcv2/packs/project_config.py +222 -0
- tdcv2/packs/registry.py +246 -0
- tdcv2/packs/source.py +190 -0
- tdcv2/packs_data/common/book/isbn10.txt +25 -0
- tdcv2/packs_data/common/book/isbn13.txt +31 -0
- tdcv2/packs_data/common/database/collation.txt +10 -0
- tdcv2/packs_data/common/database/column.txt +28 -0
- tdcv2/packs_data/common/database/engine.txt +10 -0
- tdcv2/packs_data/common/database/type.txt +21 -0
- tdcv2/packs_data/common/dev/browser.txt +12 -0
- tdcv2/packs_data/common/dev/environment.txt +12 -0
- tdcv2/packs_data/common/dev/framework.txt +31 -0
- tdcv2/packs_data/common/dev/frameworkByLanguage/C#.txt +7 -0
- tdcv2/packs_data/common/dev/frameworkByLanguage/Go.txt +7 -0
- tdcv2/packs_data/common/dev/frameworkByLanguage/Java.txt +8 -0
- tdcv2/packs_data/common/dev/frameworkByLanguage/JavaScript.txt +10 -0
- tdcv2/packs_data/common/dev/frameworkByLanguage/PHP.txt +7 -0
- tdcv2/packs_data/common/dev/frameworkByLanguage/Python.txt +10 -0
- tdcv2/packs_data/common/dev/frameworkByLanguage/Ruby.txt +6 -0
- tdcv2/packs_data/common/dev/frameworkByLanguage/Rust.txt +7 -0
- tdcv2/packs_data/common/dev/frameworkByLanguage/Swift.txt +6 -0
- tdcv2/packs_data/common/dev/frameworkByLanguage/TypeScript.txt +8 -0
- tdcv2/packs_data/common/dev/httpHeader.txt +22 -0
- tdcv2/packs_data/common/dev/languageCoherent.txt +13 -0
- tdcv2/packs_data/common/dev/logLevel.txt +9 -0
- tdcv2/packs_data/common/dev/os.txt +19 -0
- tdcv2/packs_data/common/dev/programmingLanguage.txt +37 -0
- tdcv2/packs_data/common/dev/spdxLicense.txt +18 -0
- tdcv2/packs_data/common/device/iccid.txt +36 -0
- tdcv2/packs_data/common/device/imei.txt +36 -0
- tdcv2/packs_data/common/docs/mrz/id_td1.txt +93 -0
- tdcv2/packs_data/common/docs/mrz/passport_td3.txt +105 -0
- tdcv2/packs_data/common/finance/accountType.txt +12 -0
- tdcv2/packs_data/common/finance/bic.txt +6 -0
- tdcv2/packs_data/common/finance/crypto.txt +18 -0
- tdcv2/packs_data/common/finance/currency.txt +23 -0
- tdcv2/packs_data/common/finance/currencyCode.txt +23 -0
- tdcv2/packs_data/common/finance/currencySymbol.txt +19 -0
- tdcv2/packs_data/common/finance/iban.txt +27 -0
- tdcv2/packs_data/common/finance/stockExchange.txt +18 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Avalanche.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Bitcoin.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Cardano.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Chainlink.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Cosmos.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Dogecoin.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Ethereum.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Litecoin.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Monero.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Polkadot.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Polygon.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Ripple.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Solana.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Stellar.txt +4 -0
- tdcv2/packs_data/common/finance/tickerByCrypto/Tether.txt +4 -0
- tdcv2/packs_data/common/finance/transactionType.txt +12 -0
- tdcv2/packs_data/common/geo/timezone.txt +39 -0
- tdcv2/packs_data/common/git/sha.txt +6 -0
- tdcv2/packs_data/common/id/nanoid.txt +6 -0
- tdcv2/packs_data/common/id/object_id.txt +6 -0
- tdcv2/packs_data/common/id/ulid.txt +6 -0
- tdcv2/packs_data/common/id/uuid.txt +6 -0
- tdcv2/packs_data/common/internet/domain.txt +9 -0
- tdcv2/packs_data/common/internet/email.txt +8 -0
- tdcv2/packs_data/common/internet/emoji.txt +33 -0
- tdcv2/packs_data/common/internet/httpMethod.txt +10 -0
- tdcv2/packs_data/common/internet/httpStatus.txt +25 -0
- tdcv2/packs_data/common/internet/ipv4.txt +36 -0
- tdcv2/packs_data/common/internet/ipv6.txt +6 -0
- tdcv2/packs_data/common/internet/mac.txt +6 -0
- tdcv2/packs_data/common/internet/slug.txt +6 -0
- tdcv2/packs_data/common/internet/url.txt +9 -0
- tdcv2/packs_data/common/internet/userAgent.txt +9 -0
- tdcv2/packs_data/common/internet/username.txt +6 -0
- tdcv2/packs_data/common/logistics/container_iso6346.txt +34 -0
- tdcv2/packs_data/common/payment/card/pan.txt +36 -0
- tdcv2/packs_data/common/periodical/issn.txt +25 -0
- tdcv2/packs_data/common/phone/e164.txt +6 -0
- tdcv2/packs_data/common/product/ean13.txt +31 -0
- tdcv2/packs_data/common/product/gtin14.txt +31 -0
- tdcv2/packs_data/common/product/upc_a.txt +31 -0
- tdcv2/packs_data/common/science/chemicalElement.txt +32 -0
- tdcv2/packs_data/common/science/unit.txt +45 -0
- tdcv2/packs_data/common/security/api_key.txt +6 -0
- tdcv2/packs_data/common/security/jwt.txt +9 -0
- tdcv2/packs_data/common/security/md5.txt +6 -0
- tdcv2/packs_data/common/security/otp.txt +6 -0
- tdcv2/packs_data/common/security/sha1.txt +6 -0
- tdcv2/packs_data/common/security/sha256.txt +6 -0
- tdcv2/packs_data/common/security/totp_secret.txt +6 -0
- tdcv2/packs_data/common/system/cron.txt +14 -0
- tdcv2/packs_data/common/system/directoryPath.txt +15 -0
- tdcv2/packs_data/common/system/fileExt.txt +28 -0
- tdcv2/packs_data/common/system/mimeType.txt +23 -0
- tdcv2/packs_data/common/system/semver.txt +6 -0
- tdcv2/packs_data/common/transport/airportCode.txt +37 -0
- tdcv2/packs_data/common/vehicle/brand.txt +52 -0
- tdcv2/packs_data/common/vehicle/manufacturer.txt +41 -0
- tdcv2/packs_data/common/vehicle/model/Acura.txt +10 -0
- tdcv2/packs_data/common/vehicle/model/Alfa Romeo.txt +7 -0
- tdcv2/packs_data/common/vehicle/model/Aston Martin.txt +8 -0
- tdcv2/packs_data/common/vehicle/model/Audi.txt +17 -0
- tdcv2/packs_data/common/vehicle/model/BMW.txt +17 -0
- tdcv2/packs_data/common/vehicle/model/Bentley.txt +7 -0
- tdcv2/packs_data/common/vehicle/model/Bugatti.txt +6 -0
- tdcv2/packs_data/common/vehicle/model/Buick.txt +8 -0
- tdcv2/packs_data/common/vehicle/model/Cadillac.txt +11 -0
- tdcv2/packs_data/common/vehicle/model/Chevrolet.txt +17 -0
- tdcv2/packs_data/common/vehicle/model/Chrysler.txt +7 -0
- tdcv2/packs_data/common/vehicle/model/Dodge.txt +8 -0
- tdcv2/packs_data/common/vehicle/model/Ferrari.txt +10 -0
- tdcv2/packs_data/common/vehicle/model/Fiat.txt +9 -0
- tdcv2/packs_data/common/vehicle/model/Ford.txt +17 -0
- tdcv2/packs_data/common/vehicle/model/GMC.txt +10 -0
- tdcv2/packs_data/common/vehicle/model/Genesis.txt +10 -0
- tdcv2/packs_data/common/vehicle/model/Honda.txt +15 -0
- tdcv2/packs_data/common/vehicle/model/Hyundai.txt +15 -0
- tdcv2/packs_data/common/vehicle/model/Infiniti.txt +10 -0
- tdcv2/packs_data/common/vehicle/model/Jaguar.txt +10 -0
- tdcv2/packs_data/common/vehicle/model/Jeep.txt +12 -0
- tdcv2/packs_data/common/vehicle/model/Kia.txt +16 -0
- tdcv2/packs_data/common/vehicle/model/Lamborghini.txt +7 -0
- tdcv2/packs_data/common/vehicle/model/Land Rover.txt +10 -0
- tdcv2/packs_data/common/vehicle/model/Lexus.txt +14 -0
- tdcv2/packs_data/common/vehicle/model/Lincoln.txt +8 -0
- tdcv2/packs_data/common/vehicle/model/Lotus.txt +7 -0
- tdcv2/packs_data/common/vehicle/model/Lucid.txt +6 -0
- tdcv2/packs_data/common/vehicle/model/Maserati.txt +10 -0
- tdcv2/packs_data/common/vehicle/model/Maybach.txt +6 -0
- tdcv2/packs_data/common/vehicle/model/Mazda.txt +12 -0
- tdcv2/packs_data/common/vehicle/model/McLaren.txt +8 -0
- tdcv2/packs_data/common/vehicle/model/Mercedes-Benz.txt +17 -0
- tdcv2/packs_data/common/vehicle/model/Mini.txt +8 -0
- tdcv2/packs_data/common/vehicle/model/Mitsubishi.txt +8 -0
- tdcv2/packs_data/common/vehicle/model/Nissan.txt +18 -0
- tdcv2/packs_data/common/vehicle/model/Polestar.txt +6 -0
- tdcv2/packs_data/common/vehicle/model/Porsche.txt +11 -0
- tdcv2/packs_data/common/vehicle/model/Ram.txt +9 -0
- tdcv2/packs_data/common/vehicle/model/Rivian.txt +6 -0
- tdcv2/packs_data/common/vehicle/model/Rolls-Royce.txt +9 -0
- tdcv2/packs_data/common/vehicle/model/Subaru.txt +13 -0
- tdcv2/packs_data/common/vehicle/model/Tesla.txt +9 -0
- tdcv2/packs_data/common/vehicle/model/Toyota.txt +18 -0
- tdcv2/packs_data/common/vehicle/model/Volkswagen.txt +13 -0
- tdcv2/packs_data/common/vehicle/model/Volvo.txt +11 -0
- tdcv2/packs_data/common/vehicle/model.txt +41 -0
- tdcv2/packs_data/common/vehicle/vin.txt +49 -0
- tdcv2/packs_data/countries/usa/docs/driversLicense.txt +7 -0
- tdcv2/packs_data/countries/usa/docs/medicare.txt +10 -0
- tdcv2/packs_data/countries/usa/docs/passport.txt +7 -0
- tdcv2/packs_data/countries/usa/docs/ssn.txt +9 -0
- tdcv2/packs_data/countries/usa/education/university.txt +38 -0
- tdcv2/packs_data/countries/usa/finance/aba_routing.txt +23 -0
- tdcv2/packs_data/countries/usa/finance/accountType.txt +17 -0
- tdcv2/packs_data/countries/usa/finance/bank.txt +45 -0
- tdcv2/packs_data/countries/usa/geo/city.txt +1004 -0
- tdcv2/packs_data/countries/usa/geo/county.txt +183 -0
- tdcv2/packs_data/countries/usa/geo/state.txt +60 -0
- tdcv2/packs_data/countries/usa/geo/stateAbbr.txt +60 -0
- tdcv2/packs_data/countries/usa/geo/streetName.txt +32 -0
- tdcv2/packs_data/countries/usa/geo/streetNamed.txt +65 -0
- tdcv2/packs_data/countries/usa/geo/zip.txt +6 -0
- tdcv2/packs_data/countries/usa/holiday.txt +14 -0
- tdcv2/packs_data/countries/usa/phone.txt +6 -0
- tdcv2/packs_data/countries/usa/sport/team.txt +31 -0
- tdcv2/packs_data/countries/usa/tax/ein.txt +8 -0
- tdcv2/packs_data/countries/usa/tax/filingStatus.txt +10 -0
- tdcv2/packs_data/countries/usa/tax/itin.txt +9 -0
- tdcv2/packs_data/countries/usa/vehicle/plate.txt +6 -0
- tdcv2/packs_data/en/address/buildingType.txt +18 -0
- tdcv2/packs_data/en/address/unitDesignator.txt +16 -0
- tdcv2/packs_data/en/airline/aircraftType.txt +21 -0
- tdcv2/packs_data/en/airline/name.txt +32 -0
- tdcv2/packs_data/en/animal/bird.txt +24 -0
- tdcv2/packs_data/en/animal/cat.txt +19 -0
- tdcv2/packs_data/en/animal/dog.txt +24 -0
- tdcv2/packs_data/en/animal/fish.txt +22 -0
- tdcv2/packs_data/en/animal/horse.txt +17 -0
- tdcv2/packs_data/en/animal/insect.txt +19 -0
- tdcv2/packs_data/en/animal/type.txt +34 -0
- tdcv2/packs_data/en/book/format.txt +10 -0
- tdcv2/packs_data/en/book/genre.txt +26 -0
- tdcv2/packs_data/en/clothing/shoeSizeUs.txt +18 -0
- tdcv2/packs_data/en/clothing/size.txt +12 -0
- tdcv2/packs_data/en/clothing/type.txt +19 -0
- tdcv2/packs_data/en/color/name.txt +54 -0
- tdcv2/packs_data/en/commerce/carrier.txt +14 -0
- tdcv2/packs_data/en/commerce/department.txt +32 -0
- tdcv2/packs_data/en/commerce/orderStatus.txt +17 -0
- tdcv2/packs_data/en/commerce/paymentMethod.txt +14 -0
- tdcv2/packs_data/en/commerce/paymentStatus.txt +13 -0
- tdcv2/packs_data/en/commerce/productAdjective.txt +34 -0
- tdcv2/packs_data/en/commerce/productMaterial.txt +28 -0
- tdcv2/packs_data/en/commerce/productNoun.txt +54 -0
- tdcv2/packs_data/en/commerce/returnReason.txt +16 -0
- tdcv2/packs_data/en/commerce/reviewTitle.txt +19 -0
- tdcv2/packs_data/en/commerce/shippingStatus.txt +12 -0
- tdcv2/packs_data/en/commerce/unitOfMeasure.txt +24 -0
- tdcv2/packs_data/en/company/buzzAdjective.txt +44 -0
- tdcv2/packs_data/en/company/buzzNoun.txt +44 -0
- tdcv2/packs_data/en/company/buzzVerb.txt +42 -0
- tdcv2/packs_data/en/company/industry.txt +29 -0
- tdcv2/packs_data/en/company/legalSuffix.txt +24 -0
- tdcv2/packs_data/en/company/namePart.txt +44 -0
- tdcv2/packs_data/en/date/month.txt +16 -0
- tdcv2/packs_data/en/date/monthAbbr.txt +16 -0
- tdcv2/packs_data/en/date/quarter.txt +8 -0
- tdcv2/packs_data/en/date/season.txt +8 -0
- tdcv2/packs_data/en/date/timeOfDay.txt +12 -0
- tdcv2/packs_data/en/date/weekday.txt +11 -0
- tdcv2/packs_data/en/date/weekdayAbbr.txt +11 -0
- tdcv2/packs_data/en/education/courseSubject.txt +20 -0
- tdcv2/packs_data/en/education/degree.txt +18 -0
- tdcv2/packs_data/en/education/grade.txt +17 -0
- tdcv2/packs_data/en/education/major.txt +26 -0
- tdcv2/packs_data/en/event/type.txt +16 -0
- tdcv2/packs_data/en/event/venueType.txt +15 -0
- tdcv2/packs_data/en/finance/budgetCategory.txt +21 -0
- tdcv2/packs_data/en/finance/creditScoreBand.txt +9 -0
- tdcv2/packs_data/en/finance/insuranceType.txt +16 -0
- tdcv2/packs_data/en/finance/loanType.txt +13 -0
- tdcv2/packs_data/en/food/cuisine.txt +18 -0
- tdcv2/packs_data/en/food/dish.txt +29 -0
- tdcv2/packs_data/en/food/dishByCuisine/American.txt +11 -0
- tdcv2/packs_data/en/food/dishByCuisine/Chinese.txt +12 -0
- tdcv2/packs_data/en/food/dishByCuisine/French.txt +12 -0
- tdcv2/packs_data/en/food/dishByCuisine/Greek.txt +11 -0
- tdcv2/packs_data/en/food/dishByCuisine/Indian.txt +12 -0
- tdcv2/packs_data/en/food/dishByCuisine/Italian.txt +12 -0
- tdcv2/packs_data/en/food/dishByCuisine/Japanese.txt +12 -0
- tdcv2/packs_data/en/food/dishByCuisine/Korean.txt +11 -0
- tdcv2/packs_data/en/food/dishByCuisine/Lebanese.txt +11 -0
- tdcv2/packs_data/en/food/dishByCuisine/Mexican.txt +12 -0
- tdcv2/packs_data/en/food/dishByCuisine/Spanish.txt +11 -0
- tdcv2/packs_data/en/food/dishByCuisine/Thai.txt +11 -0
- tdcv2/packs_data/en/food/dishByCuisine/Turkish.txt +11 -0
- tdcv2/packs_data/en/food/dishByCuisine/Vietnamese.txt +10 -0
- tdcv2/packs_data/en/food/fruit.txt +26 -0
- tdcv2/packs_data/en/food/ingredient.txt +28 -0
- tdcv2/packs_data/en/food/spice.txt +24 -0
- tdcv2/packs_data/en/food/vegetable.txt +26 -0
- tdcv2/packs_data/en/gaming/characterClass.txt +20 -0
- tdcv2/packs_data/en/gaming/platform.txt +13 -0
- tdcv2/packs_data/en/gaming/rank.txt +13 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Argentina.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Australia.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Bangladesh.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Brazil.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Canada.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/China.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Egypt.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/France.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Germany.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Greece.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/India.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Indonesia.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Ireland.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Italy.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Japan.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Mexico.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Netherlands.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/New Zealand.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Nigeria.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Norway.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Pakistan.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Poland.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Portugal.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Russia.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Saudi Arabia.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Singapore.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/South Africa.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/South Korea.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Spain.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Sweden.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Switzerland.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Thailand.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Turkey.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/United Kingdom.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/United States.txt +5 -0
- tdcv2/packs_data/en/geo/capitalByCountry/Vietnam.txt +5 -0
- tdcv2/packs_data/en/geo/country.txt +41 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Argentina.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Australia.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Bangladesh.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Brazil.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Canada.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/China.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Egypt.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/France.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Germany.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Greece.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/India.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Indonesia.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Ireland.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Italy.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Japan.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Mexico.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Netherlands.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/New Zealand.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Nigeria.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Norway.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Pakistan.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Poland.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Portugal.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Russia.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Saudi Arabia.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Singapore.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/South Africa.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/South Korea.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Spain.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Sweden.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Switzerland.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Thailand.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Turkey.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/United Kingdom.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/United States.txt +5 -0
- tdcv2/packs_data/en/geo/currencyByCountry/Vietnam.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Argentina.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Australia.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Bangladesh.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Brazil.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Canada.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/China.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Egypt.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/France.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Germany.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Greece.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/India.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Indonesia.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Ireland.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Italy.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Japan.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Mexico.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Netherlands.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/New Zealand.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Nigeria.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Norway.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Pakistan.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Poland.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Portugal.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Russia.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Saudi Arabia.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Singapore.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/South Africa.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/South Korea.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Spain.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Sweden.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Switzerland.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Thailand.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Turkey.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/United Kingdom.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/United States.txt +5 -0
- tdcv2/packs_data/en/geo/currencyCodeByCountry/Vietnam.txt +5 -0
- tdcv2/packs_data/en/geo/direction.txt +20 -0
- tdcv2/packs_data/en/government/agency.txt +13 -0
- tdcv2/packs_data/en/government/documentType.txt +14 -0
- tdcv2/packs_data/en/hacker/abbreviation.txt +40 -0
- tdcv2/packs_data/en/hacker/adjective.txt +24 -0
- tdcv2/packs_data/en/hacker/ingverb.txt +23 -0
- tdcv2/packs_data/en/hacker/noun.txt +30 -0
- tdcv2/packs_data/en/hacker/verb.txt +25 -0
- tdcv2/packs_data/en/hr/benefit.txt +19 -0
- tdcv2/packs_data/en/hr/interviewStage.txt +15 -0
- tdcv2/packs_data/en/hr/leaveType.txt +14 -0
- tdcv2/packs_data/en/hr/meetingType.txt +16 -0
- tdcv2/packs_data/en/legal/caseType.txt +15 -0
- tdcv2/packs_data/en/legal/court.txt +12 -0
- tdcv2/packs_data/en/legal/term.txt +16 -0
- tdcv2/packs_data/en/location/country.txt +241 -0
- tdcv2/packs_data/en/media/gameGenre.txt +19 -0
- tdcv2/packs_data/en/media/movieGenre.txt +21 -0
- tdcv2/packs_data/en/media/streamingPlatform.txt +16 -0
- tdcv2/packs_data/en/media/tvRating.txt +15 -0
- tdcv2/packs_data/en/medical/allergy.txt +21 -0
- tdcv2/packs_data/en/medical/ancestry.txt +16 -0
- tdcv2/packs_data/en/medical/bloodType.txt +12 -0
- tdcv2/packs_data/en/medical/diagnosis.txt +82 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/Ashkenazi Jewish.txt +16 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/East Asian.txt +14 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/Eastern European.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/Indigenous American.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/Mediterranean.txt +11 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/Middle Eastern.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/North African.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/Northern European.txt +14 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/Pacific Islander.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/South Asian.txt +12 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/Southeast Asian.txt +11 -0
- tdcv2/packs_data/en/medical/diagnosisByAncestry/Sub-Saharan African.txt +16 -0
- tdcv2/packs_data/en/medical/diagnosisBySpecialty/Cardiology.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisBySpecialty/Dermatology.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisBySpecialty/Endocrinology.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisBySpecialty/Gastroenterology.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisBySpecialty/Nephrology.txt +9 -0
- tdcv2/packs_data/en/medical/diagnosisBySpecialty/Neurology.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisBySpecialty/Oncology.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisBySpecialty/Orthopedics.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisBySpecialty/Psychiatry.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisBySpecialty/Pulmonology.txt +10 -0
- tdcv2/packs_data/en/medical/diagnosisFemale.txt +30 -0
- tdcv2/packs_data/en/medical/diagnosisMale.txt +24 -0
- tdcv2/packs_data/en/medical/drugGeneric.txt +38 -0
- tdcv2/packs_data/en/medical/specialty.txt +35 -0
- tdcv2/packs_data/en/medical/specialtyCoherent.txt +14 -0
- tdcv2/packs_data/en/medical/symptom.txt +39 -0
- tdcv2/packs_data/en/music/genre.txt +28 -0
- tdcv2/packs_data/en/music/instrument.txt +24 -0
- tdcv2/packs_data/en/nature/flower.txt +24 -0
- tdcv2/packs_data/en/nature/gemstone.txt +24 -0
- tdcv2/packs_data/en/nature/metal.txt +22 -0
- tdcv2/packs_data/en/nature/tree.txt +24 -0
- tdcv2/packs_data/en/person/female/diagnosis.txt +17 -0
- tdcv2/packs_data/en/person/female/firstName.txt +1005 -0
- tdcv2/packs_data/en/person/gender.txt +6 -0
- tdcv2/packs_data/en/person/hobby.txt +26 -0
- tdcv2/packs_data/en/person/householdSize.txt +11 -0
- tdcv2/packs_data/en/person/incomeBracket.txt +11 -0
- tdcv2/packs_data/en/person/language.txt +24 -0
- tdcv2/packs_data/en/person/lastName.txt +1005 -0
- tdcv2/packs_data/en/person/male/diagnosis.txt +14 -0
- tdcv2/packs_data/en/person/male/firstName.txt +1005 -0
- tdcv2/packs_data/en/person/maritalStatus.txt +11 -0
- tdcv2/packs_data/en/person/nationality.txt +29 -0
- tdcv2/packs_data/en/person/nickname.txt +44 -0
- tdcv2/packs_data/en/person/prefix.txt +21 -0
- tdcv2/packs_data/en/person/pronoun.txt +11 -0
- tdcv2/packs_data/en/person/suffix.txt +20 -0
- tdcv2/packs_data/en/person/zodiac.txt +16 -0
- tdcv2/packs_data/en/realestate/amenity.txt +22 -0
- tdcv2/packs_data/en/realestate/listingStatus.txt +14 -0
- tdcv2/packs_data/en/realestate/propertyType.txt +21 -0
- tdcv2/packs_data/en/realestate/roomType.txt +17 -0
- tdcv2/packs_data/en/social/contentType.txt +15 -0
- tdcv2/packs_data/en/social/hashtag.txt +29 -0
- tdcv2/packs_data/en/social/platform.txt +19 -0
- tdcv2/packs_data/en/social/reaction.txt +15 -0
- tdcv2/packs_data/en/sport/name.txt +28 -0
- tdcv2/packs_data/en/sport/position.txt +22 -0
- tdcv2/packs_data/en/sport/positionBySport/American Football.txt +10 -0
- tdcv2/packs_data/en/sport/positionBySport/Baseball.txt +10 -0
- tdcv2/packs_data/en/sport/positionBySport/Basketball.txt +9 -0
- tdcv2/packs_data/en/sport/positionBySport/Cricket.txt +9 -0
- tdcv2/packs_data/en/sport/positionBySport/Ice Hockey.txt +9 -0
- tdcv2/packs_data/en/sport/positionBySport/Rugby.txt +10 -0
- tdcv2/packs_data/en/sport/positionBySport/Soccer.txt +10 -0
- tdcv2/packs_data/en/sport/positionBySport/Volleyball.txt +9 -0
- tdcv2/packs_data/en/sport/sportCoherent.txt +12 -0
- tdcv2/packs_data/en/telecom/carrier.txt +16 -0
- tdcv2/packs_data/en/telecom/planType.txt +11 -0
- tdcv2/packs_data/en/text/paragraph.txt +154 -0
- tdcv2/packs_data/en/text/sentence.txt +504 -0
- tdcv2/packs_data/en/text/word.txt +404 -0
- tdcv2/packs_data/en/travel/bookingStatus.txt +12 -0
- tdcv2/packs_data/en/travel/hotelAmenity.txt +20 -0
- tdcv2/packs_data/en/travel/roomType.txt +17 -0
- tdcv2/packs_data/en/travel/starRating.txt +9 -0
- tdcv2/packs_data/en/travel/tripType.txt +16 -0
- tdcv2/packs_data/en/vehicle/bicycle.txt +16 -0
- tdcv2/packs_data/en/vehicle/fuel.txt +12 -0
- tdcv2/packs_data/en/vehicle/type.txt +18 -0
- tdcv2/packs_data/en/weather/condition.txt +18 -0
- tdcv2/packs_data/en/weather/phenomenon.txt +16 -0
- tdcv2/packs_data/en/word/adjective.txt +44 -0
- tdcv2/packs_data/en/word/adverb.txt +34 -0
- tdcv2/packs_data/en/word/noun.txt +44 -0
- tdcv2/packs_data/en/word/verb.txt +44 -0
- tdcv2/packs_data/en/work/cable/conduit.txt +11 -0
- tdcv2/packs_data/en/work/cable/type.txt +13 -0
- tdcv2/packs_data/en/work/department.txt +24 -0
- tdcv2/packs_data/en/work/employmentType.txt +13 -0
- tdcv2/packs_data/en/work/industryCoherent.txt +14 -0
- tdcv2/packs_data/en/work/jobByIndustry/Construction.txt +10 -0
- tdcv2/packs_data/en/work/jobByIndustry/Education.txt +10 -0
- tdcv2/packs_data/en/work/jobByIndustry/Finance.txt +10 -0
- tdcv2/packs_data/en/work/jobByIndustry/Healthcare.txt +10 -0
- tdcv2/packs_data/en/work/jobByIndustry/Hospitality.txt +10 -0
- tdcv2/packs_data/en/work/jobByIndustry/Legal.txt +10 -0
- tdcv2/packs_data/en/work/jobByIndustry/Manufacturing.txt +10 -0
- tdcv2/packs_data/en/work/jobByIndustry/Retail.txt +10 -0
- tdcv2/packs_data/en/work/jobByIndustry/Technology.txt +10 -0
- tdcv2/packs_data/en/work/jobByIndustry/Transportation.txt +10 -0
- tdcv2/packs_data/en/work/jobTitle.txt +189 -0
- tdcv2/packs_data/en/work/mining/method.txt +12 -0
- tdcv2/packs_data/en/work/mining/mineral.txt +21 -0
- tdcv2/packs_data/en/work/mining/shift.txt +9 -0
- tdcv2/packs_data/en/work/seniority.txt +20 -0
- tdcv2/packs_data/en/work/skill.txt +44 -0
- tdcv2/packs_data/en/work/trucking/cargoType.txt +17 -0
- tdcv2/packs_data/en/work/trucking/licenceClass.txt +7 -0
- tdcv2/packs_data/en/work/trucking/routeType.txt +11 -0
- tdcv2/packs_data/en/world/religion.txt +17 -0
- tdcv2/packs_data/en/world/writingSystem.txt +16 -0
- tdcv2/packs_data/index.txt +489 -0
- tdcv2/parser/__init__.py +5 -0
- tdcv2/parser/config_builder.py +516 -0
- tdcv2/parser/facade.py +137 -0
- tdcv2/parser/generated/TDCLexer.py +160 -0
- tdcv2/parser/generated/TDCParser.py +870 -0
- tdcv2/parser/generated/TDCParserVisitor.py +72 -0
- tdcv2/parser/generated/__init__.py +0 -0
- tdcv2/pattern/__init__.py +5 -0
- tdcv2/pattern/curve.py +301 -0
- tdcv2/pattern/density.py +133 -0
- tdcv2/pattern/gen.py +261 -0
- tdcv2/pattern/png.py +178 -0
- tdcv2/pattern/svg.py +424 -0
- tdcv2/prng/__init__.py +6 -0
- tdcv2/prng/permute.py +102 -0
- tdcv2/prng/prng.py +141 -0
- tdcv2/prng/rand.py +34 -0
- tdcv2/prng/seekable.py +60 -0
- tdcv2/sequence/__init__.py +5 -0
- tdcv2/sequence/pool.py +132 -0
- tdcv2/sequence/uniq.py +264 -0
- tdcv2/sequence/uniq_simple.py +175 -0
- tdcv2/stats/__init__.py +5 -0
- tdcv2/stats/distribution.py +249 -0
- tdcv2/stats/special.py +174 -0
- tdcv2/stats/timeseries.py +89 -0
- tdcv2/tdc.py +465 -0
- tdcv2/unicode/__init__.py +5 -0
- tdcv2/unicode/alphabets.py +59 -0
- tdcv2/unicode/char_set.py +57 -0
- tdcv2/validator/__init__.py +5 -0
- tdcv2/validator/checks.py +101 -0
- tdcv2/validator/compute_check.py +324 -0
- tdcv2/validator/validate.py +2912 -0
- tdcv2-0.1.2.dist-info/METADATA +230 -0
- tdcv2-0.1.2.dist-info/RECORD +610 -0
- tdcv2-0.1.2.dist-info/WHEEL +5 -0
- tdcv2-0.1.2.dist-info/entry_points.txt +2 -0
- tdcv2-0.1.2.dist-info/licenses/LICENSE +21 -0
- tdcv2-0.1.2.dist-info/top_level.txt +1 -0
tdcv2/__init__.py
ADDED
tdcv2/cli/__init__.py
ADDED
tdcv2/cli/__main__.py
ADDED
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()
|